58using namespace std::placeholders;
66#include <glsl_kicad_frag.h>
67#include <glsl_kicad_vert.h>
79constexpr GLuint STENCIL_DOTS_MARKER = 0x01;
81constexpr GLuint STENCIL_GRID_COVERAGE = 0x80;
88 wxGLAttributes attribs;
89 attribs.RGBA().DoubleBuffer().Depth( 8 ).EndList();
150 glDeleteTextures( 1, &bitmap.second.id );
156#ifndef DISABLE_BITMAP_CACHE
162 if( glIsTexture( it->second.id ) )
164 it->second.accessTime = wxGetUTCTimeMillis().GetValue();
165 return it->second.id;
170 glDeleteTextures( 1, &it->second.id );
198 return std::numeric_limits< GLuint >::max();
200 wxImage imgData = *imgPtr;
203 GLint maxTextureSize;
204 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
206 int imgWidth = imgData.GetWidth();
207 int imgHeight = imgData.GetHeight();
209 if( imgWidth > maxTextureSize || imgHeight > maxTextureSize )
213 double scaleX =
static_cast<double>( maxTextureSize ) / imgWidth;
214 double scaleY =
static_cast<double>( maxTextureSize ) / imgHeight;
215 double scale = std::min( scaleX, scaleY );
217 int newWidth = std::clamp(
KiROUND( imgWidth *
scale ), 1, maxTextureSize );
218 int newHeight = std::clamp(
KiROUND( imgHeight *
scale ), 1, maxTextureSize );
220 imgData = imgData.Scale( newWidth, newHeight, wxIMAGE_QUALITY_HIGH );
222 if( !imgData.IsOk() )
223 return std::numeric_limits< GLuint >::max();
226 bmp.
w = imgData.GetSize().x;
227 bmp.
h = imgData.GetSize().y;
233 glGenTextures( 1, &textureID );
241 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
243 if( imgData.HasAlpha() || imgData.HasMask() )
245 bmp.
size =
static_cast<size_t>( bmp.
w ) * bmp.
h * 4;
246 auto buf = std::make_unique<uint8_t[]>( bmp.
size );
248 uint8_t* dstP = buf.get();
249 uint8_t* srcP = imgData.GetData();
251 long long pxCount =
static_cast<long long>( bmp.
w ) * bmp.
h;
253 if( imgData.HasAlpha() )
255 uint8_t* srcAlpha = imgData.GetAlpha();
257 for(
long long px = 0; px < pxCount; px++ )
259 memcpy( dstP, srcP, 3 );
267 else if( imgData.HasMask() )
269 uint8_t maskRed = imgData.GetMaskRed();
270 uint8_t maskGreen = imgData.GetMaskGreen();
271 uint8_t maskBlue = imgData.GetMaskBlue();
273 for(
long long px = 0; px < pxCount; px++ )
275 memcpy( dstP, srcP, 3 );
277 if( srcP[0] == maskRed && srcP[1] == maskGreen && srcP[2] == maskBlue )
278 dstP[3] = wxALPHA_TRANSPARENT;
280 dstP[3] = wxALPHA_OPAQUE;
287 glBindTexture( GL_TEXTURE_2D, textureID );
288 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, bmp.
w, bmp.
h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
293 bmp.
size =
static_cast<size_t>( bmp.
w ) * bmp.
h * 3;
295 uint8_t* srcP = imgData.GetData();
297 glBindTexture( GL_TEXTURE_2D, textureID );
298 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, bmp.
w, bmp.
h, 0, GL_RGB, GL_UNSIGNED_BYTE, srcP );
301 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
302 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
304 long long currentTime = wxGetUTCTimeMillis().GetValue();
309#ifndef DISABLE_BITMAP_CACHE
319 for(
const auto& [kiid, cachedBmp] :
m_bitmaps )
321 const int cacheTimeoutMillis = 1000L;
323 if( currentTime - cachedBmp.accessTime > cacheTimeoutMillis )
337 toRemove = *toRemoveLru;
343 glDeleteTextures( 1, &cachedBitmap.
id );
361 wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
362 const wxString& aName ) :
363 GAL( aDisplayOptions ),
387 throw std::runtime_error(
"Could not create the main OpenGL context" );
396 throw std::runtime_error(
"Could not create a private OpenGL context" );
442#if defined _WIN32 || defined _WIN64
449 SetSize( aParent->GetClientSize() );
460 gluTessProperty(
m_tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
560 static std::optional<wxString> cached;
562 if( cached.has_value() )
565 wxString retVal = wxEmptyString;
567 wxFrame* testFrame =
new wxFrame(
nullptr, wxID_ANY, wxT(
"" ), wxDefaultPosition,
568 wxSize( 1, 1 ), wxFRAME_TOOL_WINDOW | wxNO_BORDER );
590 catch( std::runtime_error& err )
593 retVal = wxString( err.what() );
654#ifdef KICAD_GAL_PROFILE
655 PROF_TIMER totalRealTime(
"OPENGL_GAL::beginDrawing()",
true );
658 wxASSERT_MSG(
m_isContextLocked,
"GAL_DRAWING_CONTEXT RAII object should have locked context. "
659 "Calling GAL::beginDrawing() directly is not allowed." );
661 wxASSERT_MSG(
IsVisible(),
"GAL::beginDrawing() must not be entered when GAL is not visible. "
662 "Other drawing routines will expect everything to be initialized "
663 "which will not be the case." );
669 glMatrixMode( GL_PROJECTION );
692 catch(
const std::runtime_error& )
694 wxLogVerbose(
"Could not create a framebuffer for diff mode blending.\n" );
701 catch(
const std::runtime_error& )
703 wxLogVerbose(
"Could not create a framebuffer for overlays.\n" );
713 glDisable( GL_TEXTURE_2D );
715 glShadeModel( GL_FLAT );
718 glEnable( GL_DEPTH_TEST );
719 glDepthFunc( GL_LESS );
722 glEnable( GL_BLEND );
723 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
725 glMatrixMode( GL_MODELVIEW );
729 GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
739 glLoadMatrixd( matrixData );
758 const GLint FONT_TEXTURE_UNIT = 2;
763 glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
768 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
769 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
770 checkGlError(
"loading bitmap font", __FILE__, __LINE__ );
772 glActiveTexture( GL_TEXTURE0 );
778 glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
780 glActiveTexture( GL_TEXTURE0 );
787 checkGlError(
"setting bitmap font sampler as shader parameter", __FILE__, __LINE__ );
797 double pixelSizeMultiplier =
m_compositor->GetAntialiasSupersamplingFactor();
800 renderingOffset.
x *= screenPixelSize.
x;
801 renderingOffset.
y *= screenPixelSize.
y;
808 glActiveTexture( GL_TEXTURE0 );
813#ifdef KICAD_GAL_PROFILE
814 totalRealTime.
Stop();
815 wxLogTrace(
traceGalProfile, wxT(
"OPENGL_GAL::beginDrawing(): %.1f ms" ),
816 totalRealTime.
msecs() );
839 PROF_TIMER cntEndNoncached(
"gl-end-noncached" );
849 cntEndNoncached.
Start();
851 cntEndNoncached.
Stop();
853 cntEndCached.
Start();
857 cntEndOverlay.
Start();
863 cntEndOverlay.
Stop();
865 cntComposite.
Start();
868 glColor4d( 1.0, 1.0, 1.0, 1.0 );
887#ifdef KICAD_GAL_PROFILE
909 glGetIntegerv( GL_VIEWPORT, viewport );
911 const int w = viewport[2];
912 const int h = viewport[3];
914 GLint readBuffer = GL_COLOR_ATTACHMENT0;
915 glGetIntegerv( GL_DRAW_BUFFER, &readBuffer );
921 std::vector<unsigned char> rgba( (
size_t) w * h * 4 );
924 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
925 glReadBuffer( (
GLenum) readBuffer );
926 glReadPixels( 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgba.data() );
929 unsigned char* rgb = (
unsigned char*) malloc( (
size_t) w * h * 3 );
930 unsigned char* alpha = (
unsigned char*) malloc( (
size_t) w * h );
932 for(
int i = 0; i < w * h; ++i )
934 rgb[i * 3 + 0] = rgba[i * 4 + 0];
935 rgb[i * 3 + 1] = rgba[i * 4 + 1];
936 rgb[i * 3 + 2] = rgba[i * 4 + 2];
937 alpha[i] = rgba[i * 4 + 3];
940 aDstImage.SetData( rgb, w, h,
false );
941 aDstImage.SetAlpha( alpha,
false );
943 aDstImage = aDstImage.Mirror(
false );
989 if( glGetGraphicsResetStatus )
990 return glGetGraphicsResetStatus();
992 if( glGetGraphicsResetStatusARB )
993 return glGetGraphicsResetStatusARB();
1004 if( status != GL_NO_ERROR )
1007 return status != GL_NO_ERROR;
1021 bool mainOwned =
false;
1050 if( GL_RESET_BUDGET::CLOCK::now() -
m_resetDetectedAt >= std::chrono::seconds( 2 ) )
1052 wxLogTrace(
traceGalContext, wxS(
"GL reset did not report completion, rebuilding anyway" ) );
1071 wxASSERT_MSG(
m_isContextLocked,
"Context not locked. A GAL_CONTEXT_LOCKER RAII object must "
1072 "be stacked rather than making separate lock/unlock calls." );
1075 "Context was locked by a different client. "
1076 "Should not be possible with RAII objects." );
1091 wxASSERT_MSG(
m_isContextLocked,
"GAL_UPDATE_CONTEXT RAII object should have locked context. "
1092 "Calling this from anywhere else is not allowed." );
1094 wxASSERT_MSG(
IsVisible(),
"GAL::beginUpdate() must not be entered when GAL is not visible. "
1095 "Other update routines will expect everything to be initialized "
1096 "which will not be the case." );
1132 VECTOR2D startEndVector = aEndPoint - aStartPoint;
1139 float startX =
static_cast<float>( aStartPoint.
x );
1140 float startY =
static_cast<float>( aStartPoint.
y );
1141 float endX =
static_cast<float>( aEndPoint.
x );
1142 float endY =
static_cast<float>( aEndPoint.
y );
1144 if( startX == endX && startY == endY )
1146 drawCircle( aStartPoint, aWidth / 2, aReserve );
1281 double startAngle = aStartAngle.
AsRadians();
1282 double endAngle = startAngle + aAngle.
AsRadians();
1299 for( alpha = startAngle; ( alpha + alphaIncrement ) < endAngle; )
1305 alpha += alphaIncrement;
1311 const VECTOR2D endPoint( cos( endAngle ) * aRadius, sin( endAngle ) * aRadius );
1324 VECTOR2D p( cos( startAngle ) * aRadius, sin( startAngle ) * aRadius );
1326 unsigned int lineCount = 0;
1328 for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement )
1331 if( alpha != endAngle )
1336 for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement )
1338 VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
1345 if( alpha != endAngle )
1347 VECTOR2D p_last( cos( endAngle ) * aRadius, sin( endAngle ) * aRadius );
1358 double aWidth,
double aMaxError )
1369 double startAngle = aStartAngle.
AsRadians();
1370 double endAngle = startAngle + aAngle.
AsRadians();
1378 double alphaIncrement = 2.0 *
M_PI / segCount360;
1383 int seg_count =
KiROUND( ( endAngle - startAngle ) / alphaIncrement );
1385 if( seg_count % 2 != 0 )
1389 if( seg_count == 0 )
1391 VECTOR2D p_start( aCenterPoint.
x + cos( startAngle ) * aRadius,
1392 aCenterPoint.
y + sin( startAngle ) * aRadius );
1394 VECTOR2D p_end( aCenterPoint.
x + cos( endAngle ) * aRadius,
1395 aCenterPoint.
y + sin( endAngle ) * aRadius );
1402 alphaIncrement = ( endAngle - startAngle ) / seg_count;
1412 double width = aWidth / 2.0;
1413 VECTOR2D startPoint( cos( startAngle ) * aRadius, sin( startAngle ) * aRadius );
1414 VECTOR2D endPoint( cos( endAngle ) * aRadius, sin( endAngle ) * aRadius );
1419 VECTOR2D pOuter( cos( startAngle ) * ( aRadius + width ),
1420 sin( startAngle ) * ( aRadius + width ) );
1422 VECTOR2D pInner( cos( startAngle ) * ( aRadius - width ),
1423 sin( startAngle ) * ( aRadius - width ) );
1427 for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement )
1429 VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ),
1430 sin( alpha ) * ( aRadius + width ) );
1431 VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ),
1432 sin( alpha ) * ( aRadius - width ) );
1437 pOuter = pNextOuter;
1438 pInner = pNextInner;
1442 if( alpha != endAngle )
1444 VECTOR2D pLastOuter( cos( endAngle ) * ( aRadius + width ),
1445 sin( endAngle ) * ( aRadius + width ) );
1446 VECTOR2D pLastInner( cos( endAngle ) * ( aRadius - width ),
1447 sin( endAngle ) * ( aRadius - width ) );
1459 VECTOR2D p( cos( startAngle ) * aRadius, sin( startAngle ) * aRadius );
1464 for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement )
1470 if( alpha != endAngle )
1477 for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement )
1479 VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
1486 if( alpha != endAngle )
1488 VECTOR2D p_last( cos( endAngle ) * aRadius, sin( endAngle ) * aRadius );
1500 if( aMajorRadius <= 0 || aMinorRadius <= 0 )
1503 const double alphaIncrement =
calcAngleStep( aMajorRadius );
1504 const double cosPhi = std::cos( aRotation.
AsRadians() );
1505 const double sinPhi = std::sin( aRotation.
AsRadians() );
1507 auto eval = [&](
double theta ) ->
VECTOR2D
1509 const double lx = aMajorRadius * std::cos( theta );
1510 const double ly = aMinorRadius * std::sin( theta );
1511 return VECTOR2D( lx * cosPhi - ly * sinPhi, lx * sinPhi + ly * cosPhi );
1524 for( alpha = 0.0; ( alpha + alphaIncrement ) < 2.0 *
M_PI; )
1527 alpha += alphaIncrement;
1551 unsigned int lineCount = 0;
1554 for( countAlpha = alphaIncrement; countAlpha < 2.0 *
M_PI; countAlpha += alphaIncrement )
1564 for( alpha = alphaIncrement; alpha < 2.0 *
M_PI; alpha += alphaIncrement )
1566 const VECTOR2D p_next = eval( alpha );
1582 if( aMajorRadius <= 0 || aMinorRadius <= 0 )
1585 double startAngle = aStartAngle.
AsRadians();
1586 double endAngle = aEndAngle.
AsRadians();
1589 const double alphaIncrement =
calcAngleStep( aMajorRadius );
1590 const double cosPhi = std::cos( aRotation.
AsRadians() );
1591 const double sinPhi = std::sin( aRotation.
AsRadians() );
1593 auto eval = [&](
double theta ) ->
VECTOR2D
1595 const double lx = aMajorRadius * std::cos( theta );
1596 const double ly = aMinorRadius * std::sin( theta );
1597 return VECTOR2D( lx * cosPhi - ly * sinPhi, lx * sinPhi + ly * cosPhi );
1611 for( alpha = startAngle; ( alpha + alphaIncrement ) < endAngle; )
1614 alpha += alphaIncrement;
1625 const VECTOR2D p2 = eval( endAngle );
1637 unsigned int lineCount = 0;
1640 for( countAlpha = startAngle + alphaIncrement; countAlpha <= endAngle; countAlpha += alphaIncrement )
1643 if( countAlpha != endAngle )
1651 for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement )
1653 const VECTOR2D p_next = eval( alpha );
1659 if( alpha != endAngle )
1661 const VECTOR2D p_last = eval( endAngle );
1673 VECTOR2D diagonalPointA( aEndPoint.
x, aStartPoint.
y );
1674 VECTOR2D diagonalPointB( aStartPoint.
x, aEndPoint.
y );
1700 if( aStartPoint == aEndPoint )
1706 std::deque<VECTOR2D> pointList;
1708 pointList.push_back( aStartPoint );
1709 pointList.push_back( diagonalPointA );
1710 pointList.push_back( aEndPoint );
1711 pointList.push_back( diagonalPointB );
1712 pointList.push_back( aStartPoint );
1724 return aPointList[idx];
1726 aPointList.size(), aWidth );
1740 return aLineChain.
CPoint( idx );
1742 numPoints, aWidth );
1751 return aPointList[idx];
1753 aPointList.size() );
1762 return aPointList[idx];
1764 aPointList.size() );
1773 return aPointList[idx];
1789 return aLineChain.
CPoint( idx );
1797 int lineQuadCount = 0;
1799 for(
const std::vector<VECTOR2D>& points : aPointList )
1800 lineQuadCount += points.size() - 1;
1804 for(
const std::vector<VECTOR2D>& points : aPointList )
1811 points.size(),
false );
1818 wxCHECK( aPointList.size() >= 2, );
1819 auto points = std::unique_ptr<GLdouble[]>(
new GLdouble[3 * aPointList.size()] );
1820 GLdouble* ptr = points.get();
1822 for(
const VECTOR2D& p : aPointList )
1835 wxCHECK( aListSize >= 2, );
1836 auto points = std::unique_ptr<GLdouble[]>(
new GLdouble[3 * aListSize] );
1837 GLdouble* target = points.get();
1840 for(
int i = 0; i < aListSize; ++i )
1853 bool aStrokeTriangulation )
1860 int totalTriangleCount = 0;
1875 for(
size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
1878 triPoly->GetTriangle( i, a, b, c );
1890 const auto& poly = aPolySet.
Polygon( j );
1892 for(
const auto& lc : poly )
1901 aStrokeTriangulation =
true;
1905 if( aStrokeTriangulation )
1914 for(
size_t i = 0; i < triPoly->GetTriangleCount(); i++ )
1917 triPoly->GetTriangle( i, a, b, c );
1949 std::unique_ptr<GLdouble[]> points(
new GLdouble[3 * pointCount] );
1950 GLdouble* ptr = points.get();
1952 for(
int i = 0; i < pointCount; ++i )
1966 double aFilterValue )
1968 std::vector<VECTOR2D> output;
1969 std::vector<VECTOR2D> pointCtrl;
1971 pointCtrl.push_back( aStartPoint );
1972 pointCtrl.push_back( aControlPointA );
1973 pointCtrl.push_back( aControlPointB );
1974 pointCtrl.push_back( aEndPoint );
1977 converter.
GetPoly( output, aFilterValue );
1979 if( output.size() == 1 )
1980 output.push_back( output.front() );
1988 GLfloat alpha = std::clamp( alphaBlend, 0.0, 1.0 );
1998 glm::vec4 v0 = xform * glm::vec4( -w / 2, -h / 2, 0.0, 0.0 );
1999 glm::vec4
v1 = xform * glm::vec4( w / 2, -h / 2, 0.0, 0.0 );
2000 glm::vec4
v2 = xform * glm::vec4( w / 2, h / 2, 0.0, 0.0 );
2001 glm::vec4
v3 = xform * glm::vec4( -w / 2, h / 2, 0.0, 0.0 );
2002 glm::vec4 trans = xform[3];
2006 if( !glIsTexture( texture_id ) )
2009 GLboolean depthMask = GL_TRUE;
2010 glGetBooleanv( GL_DEPTH_WRITEMASK, &depthMask );
2013 glDepthMask( GL_FALSE );
2015 glDepthFunc( GL_ALWAYS );
2017 glAlphaFunc( GL_GREATER, 0.01f );
2018 glEnable( GL_ALPHA_TEST );
2020 glMatrixMode( GL_TEXTURE );
2022 glTranslated( 0.5, 0.5, 0.5 );
2024 glTranslated( -0.5, -0.5, -0.5 );
2026 glMatrixMode( GL_MODELVIEW );
2028 glTranslated( trans.x, trans.y, trans.z );
2030 glEnable( GL_TEXTURE_2D );
2031 glActiveTexture( GL_TEXTURE0 );
2032 glBindTexture( GL_TEXTURE_2D, texture_id );
2034 float texStartX = aBitmap.
IsMirroredX() ? 1.0 : 0.0;
2035 float texEndX = aBitmap.
IsMirroredX() ? 0.0 : 1.0;
2036 float texStartY = aBitmap.
IsMirroredY() ? 1.0 : 0.0;
2037 float texEndY = aBitmap.
IsMirroredY() ? 0.0 : 1.0;
2039 glBegin( GL_QUADS );
2040 glColor4f( 1.0, 1.0, 1.0, alpha );
2041 glTexCoord2f( texStartX, texStartY );
2043 glColor4f( 1.0, 1.0, 1.0, alpha );
2044 glTexCoord2f( texEndX, texStartY);
2046 glColor4f( 1.0, 1.0, 1.0, alpha );
2047 glTexCoord2f( texEndX, texEndY);
2049 glColor4f( 1.0, 1.0, 1.0, alpha );
2050 glTexCoord2f( texStartX, texEndY);
2054 glBindTexture( GL_TEXTURE_2D, 0 );
2056#ifdef DISABLE_BITMAP_CACHE
2057 glDeleteTextures( 1, &texture_id );
2062 glMatrixMode( GL_TEXTURE );
2064 glMatrixMode( GL_MODELVIEW );
2066 glDisable( GL_ALPHA_TEST );
2068 glDepthMask( depthMask );
2070 glDepthFunc( GL_LESS );
2079 || aText.Contains( wxT(
"^{" ) )
2080 || aText.Contains( wxT(
"_{" ) )
2081 || aText.Contains( wxT(
"\n" ) ) )
2092 double overbarHeight = textSize.
y;
2123 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
2139 overbarHeight = -textSize.
y / 2.0;
2143 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
2147 int overbarLength = 0;
2148 int overbarDepth = -1;
2149 int braceNesting = 0;
2151 auto iterateString =
2152 [&](
const std::function<void(
int aOverbarLength,
int aOverbarHeight )>& overbarFn,
2153 const std::function<int(
unsigned long aChar )>& bitmapCharFn )
2157 wxASSERT_MSG( *chIt !=
'\n' && *chIt !=
'\r',
2158 "No support for multiline bitmap text yet" );
2160 if( *chIt ==
'~' && overbarDepth == -1 )
2164 if( ++lookahead !=
end && *lookahead ==
'{' )
2167 overbarDepth = braceNesting;
2172 else if( *chIt ==
'{' )
2176 else if( *chIt ==
'}' )
2178 if( braceNesting > 0 )
2181 if( braceNesting == overbarDepth )
2183 overbarFn( overbarLength, overbarHeight );
2191 if( overbarDepth != -1 )
2192 overbarLength += bitmapCharFn( *chIt );
2194 bitmapCharFn( *chIt );
2201 int overbarsCount = 0;
2204 [&overbarsCount](
int aOverbarLength,
int aOverbarHeight )
2208 [&charsCount](
unsigned long aChar ) ->
int
2224 [&](
int aOverbarLength,
int aOverbarHeight )
2228 [&](
unsigned long aChar ) ->
int
2236 if( overbarDepth != -1 && overbarLength > 0 )
2266 if( renderGlobalGrid )
2288 if( renderGlobalGrid )
2312 const double rMax = src.
extent.
x;
2313 const double phiMax = src.
extent.
y;
2315 if( rMax > 0.0 && phiMax > 0.0 )
2317 if( phiMax >= 2 *
M_PI - 1e-6 )
2323 const int kArcSegments = std::max( 16, (
int) ( phiMax / (
M_PI / 16 ) ) );
2324 std::deque<VECTOR2D> poly;
2325 poly.emplace_back( 0.0, 0.0 );
2327 for(
int i = 0; i <= kArcSegments; ++i )
2329 const double phi = phiMax * i / kArcSegments;
2330 poly.emplace_back( rMax * std::cos( phi ), rMax * std::sin( phi ) );
2333 poly.emplace_back( 0.0, 0.0 );
2345 default: wxFAIL_MSG( wxT(
"drawGridCoverageShape: unhandled GRID_SOURCE::KIND" ) );
break;
2359 std::vector<const GRID_SOURCE*> ordered;
2364 if( !src.highlighted )
2365 ordered.push_back( &src );
2370 if( src.highlighted )
2371 ordered.push_back( &src );
2375 const float majorLineWidth = minorLineWidth * 2.0f;
2378 glDisable( GL_DEPTH_TEST );
2379 glDisable( GL_TEXTURE_2D );
2382 glEnable( GL_STENCIL_TEST );
2383 glStencilMask( 0xFF );
2384 glClear( GL_STENCIL_BUFFER_BIT );
2391 const GLuint coverageMask = src.
highlighted ? 0 : STENCIL_GRID_COVERAGE;
2393 glStencilMask( 0x00 );
2394 glStencilFunc( GL_EQUAL, 0, coverageMask );
2395 glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
2414 glColor4d( color.
r, color.
g, color.
b, color.
a );
2422 const unsigned tick = ( src.
tick > 0 ) ? src.
tick :
static_cast<unsigned>(
m_gridTick );
2423 const double threshold =
2427 auto drawCrossAt = [&](
const VECTOR2D& pos,
bool aMajor,
double aArmAngle )
2429 const float w = aMajor ? majorLineWidth : minorLineWidth;
2430 const double len = 2.0 * w;
2431 const double c = std::cos( aArmAngle );
2432 const double s = std::sin( aArmAngle );
2433 const VECTOR2D arm1( c * len, s * len );
2434 const VECTOR2D arm2( -s * len, c * len );
2439 DrawLine( pos - arm1, pos + arm1 );
2440 DrawLine( pos - arm2, pos + arm2 );
2444 auto beginLines = [&]()
2451 auto drawDotsViaStencil = [&](
auto&& aMarkAxis,
auto&& aRenderAxis )
2454 glStencilMask( STENCIL_DOTS_MARKER );
2455 glClear( GL_STENCIL_BUFFER_BIT );
2458 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
2459 glStencilFunc( GL_EQUAL, STENCIL_DOTS_MARKER, coverageMask );
2460 glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
2467 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
2468 glStencilMask( 0x00 );
2469 glStencilFunc( GL_EQUAL, STENCIL_DOTS_MARKER, STENCIL_DOTS_MARKER | coverageMask );
2470 glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
2482 double dPhi = src.
pitch.
y;
2490 rMax = std::hypot( farX, farY ) * 1.01;
2504 wxASSERT( dr > 0.0 && dPhi > 0.0 );
2506 auto drawArcs = [&]()
2509 for(
double r = 0; r <= rMax + 1e-6; r += dr, ++rIdx )
2514 SetLineWidth( ( tick && rIdx % (
int) tick == 0 ) ? majorLineWidth : minorLineWidth );
2519 auto drawSpokes = [&]()
2522 for(
double phi = 0; phi <= phiMax + 1e-6; phi += dPhi, ++pIdx )
2524 SetLineWidth( ( tick && pIdx % (
int) tick == 0 ) ? majorLineWidth : minorLineWidth );
2525 const double cx = std::cos( phi );
2526 const double cy = std::sin( phi );
2539 drawDotsViaStencil( drawArcs, drawSpokes );
2544 for(
double r = 0; r <= rMax + 1e-6; r += dr, ++rIdx )
2547 for(
double phi = 0; phi <= phiMax + 1e-6; phi += dPhi, ++pIdx )
2549 const bool major = tick && ( rIdx % (int) tick == 0 ) && ( pIdx % (
int) tick == 0 );
2550 const VECTOR2D pos( r * std::cos( phi ), r * std::sin( phi ) );
2551 drawCrossAt( pos, major, phi );
2564 const double minPitch = std::min( dx, dy );
2567 if( sparsed != minPitch )
2569 const double scale = sparsed / minPitch;
2574 wxASSERT( dx > 0.0 && dy > 0.0 );
2576 double xMin, xMax, yMin, yMax;
2577 int ixMin, ixMax, iyMin, iyMax;
2588 yMin = localBBox.
GetTop();
2591 ixMin = (int) std::floor( xMin / dx );
2592 ixMax = (int) std::ceil( xMax / dx );
2593 iyMin = (int) std::floor( yMin / dy );
2594 iyMax = (int) std::ceil( yMax / dy );
2602 ixMin = (int) -( src.
extent.
x / dx );
2603 ixMax = (int) ( src.
extent.
x / dx );
2604 iyMin = (int) -( src.
extent.
y / dy );
2605 iyMax = (int) ( src.
extent.
y / dy );
2608 auto drawVerticals = [&]()
2610 for(
int ix = ixMin; ix <= ixMax; ++ix )
2612 const double x = ix * dx;
2618 SetLineWidth( ( tick &&
std::abs( ix ) % (
int) tick == 0 ) ? majorLineWidth : minorLineWidth );
2623 auto drawHorizontals = [&]()
2625 for(
int iy = iyMin; iy <= iyMax; ++iy )
2627 const double y = iy * dy;
2632 SetLineWidth( ( tick &&
std::abs( iy ) % (
int) tick == 0 ) ? majorLineWidth : minorLineWidth );
2645 drawDotsViaStencil( drawVerticals, drawHorizontals );
2649 for(
int ix = ixMin; ix <= ixMax; ++ix )
2651 for(
int iy = iyMin; iy <= iyMax; ++iy )
2654 tick && (
std::abs( ix ) % (int) tick == 0 ) && (
std::abs( iy ) % (int) tick == 0 );
2655 drawCrossAt(
VECTOR2D( ix * dx, iy * dy ), major, 0.0 );
2662 default: wxFAIL_MSG( wxT(
"drawGridSources: unhandled GRID_SOURCE::KIND" ) );
break;
2671 glStencilMask( 0x00 );
2672 glStencilFunc( GL_EQUAL, 0, coverageMask );
2673 glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
2686 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
2687 glStencilMask( STENCIL_GRID_COVERAGE );
2688 glStencilFunc( GL_ALWAYS, STENCIL_GRID_COVERAGE, STENCIL_GRID_COVERAGE );
2689 glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
2696 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
2700 glDisable( GL_STENCIL_TEST );
2702 glEnable( GL_DEPTH_TEST );
2703 glEnable( GL_TEXTURE_2D );
2713 m_compositor->Resize( aWidth * scaleFactor, aHeight * scaleFactor );
2716 wxGLCanvas::SetSize( aWidth, aHeight );
2722 bool s = wxGLCanvas::Show( aShow );
2725 wxGLCanvas::Raise();
2743 glClearColor( 0, 0, 0, 1 );
2744 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
2750 GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
2752 matrixData[0] = aTransformation.
m_data[0][0];
2753 matrixData[1] = aTransformation.
m_data[1][0];
2754 matrixData[2] = aTransformation.
m_data[2][0];
2755 matrixData[4] = aTransformation.
m_data[0][1];
2756 matrixData[5] = aTransformation.
m_data[1][1];
2757 matrixData[6] = aTransformation.
m_data[2][1];
2758 matrixData[12] = aTransformation.
m_data[0][2];
2759 matrixData[13] = aTransformation.
m_data[1][2];
2760 matrixData[14] = aTransformation.
m_data[2][2];
2762 glMultMatrixd( matrixData );
2800 std::shared_ptr<VERTEX_ITEM> newItem = std::make_shared<VERTEX_ITEM>( *
m_cachedManager );
2802 m_groups.insert( std::make_pair( groupNumber, newItem ) );
2935 wxLogTrace(
traceGalXorMode, wxT(
"OPENGL_GAL::StartDiffLayer() called" ) );
2942 wxLogTrace(
traceGalXorMode, wxT(
"StartDiffLayer(): setting target to TARGET_TEMP" ) );
2949 wxLogTrace(
traceGalXorMode, wxT(
"StartDiffLayer(): TARGET_TEMP set and cleared, compositor buffer=%u" ),
2954 wxLogTrace(
traceGalXorMode, wxT(
"StartDiffLayer(): WARNING - no temp buffer!" ) );
2961 wxLogTrace(
traceGalXorMode, wxT(
"OPENGL_GAL::EndDiffLayer() called" ) );
2962 wxLogTrace(
traceGalXorMode, wxT(
"EndDiffLayer(): m_tempBuffer=%u, m_mainBuffer=%u" ),
2967 wxLogTrace(
traceGalXorMode, wxT(
"EndDiffLayer(): using temp buffer path" ) );
2972 wxLogTrace(
traceGalXorMode, wxT(
"EndDiffLayer(): calling DrawBufferDifference" ) );
2980 wxLogTrace(
traceGalXorMode, wxT(
"EndDiffLayer(): DrawBufferDifference returned" ) );
2984 wxLogTrace(
traceGalXorMode, wxT(
"EndDiffLayer(): NO temp buffer, using fallback path" ) );
2987 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
2989 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
2992 wxLogTrace(
traceGalXorMode, wxT(
"OPENGL_GAL::EndDiffLayer() complete" ) );
3004#if wxCHECK_VERSION( 3, 3, 0 )
3016#if wxCHECK_VERSION( 3, 3, 0 )
3035 const bool aReserve )
3053 * glm::vec4( aStartPoint.
x, aStartPoint.
y, 0.0, 0.0 );
3055 * glm::vec4( aEndPoint.
x, aEndPoint.
y, 0.0, 0.0 );
3139 double outerRadius = aRadius + (
m_lineWidth / 2 );
3185 GLdouble* point = aPoints;
3187 for(
int i = 0; i < aPointCount; ++i )
3205 return VECTOR2D( aPoints[idx * 3], aPoints[idx * 3 + 1] );
3215 wxCHECK( aPointCount > 0, );
3219 if( aPointCount == 1 )
3221 drawLineQuad( aPointGetter( 0 ), aPointGetter( 0 ), aReserve );
3230 for(
int i = 1; i < aPointCount; ++i )
3232 auto start = aPointGetter( i - 1 );
3233 auto end = aPointGetter( i );
3241 int aPointCount,
double aWidth,
bool aReserve )
3243 wxCHECK( aPointCount >= 2, );
3249 for(
int i = 1; i < aPointCount; ++i )
3251 auto start = aPointGetter( i - 1 );
3252 auto end = aPointGetter( i );
3254 float startx = start.x;
3255 float starty = start.y;
3264 if( startx == endx && starty == endy )
3276 vertices += 6 + 6 + 3 + 3;
3282 for(
int i = 1; i < aPointCount; ++i )
3284 auto start = aPointGetter( i - 1 );
3285 auto end = aPointGetter( i );
3304 double spaceWidth = g->
advance * 0.74;
3322 const float XOFF = glyph->
minx;
3325 const float round_adjust = ( glyph->
maxy - glyph->
miny )
3328 const float YOFF = round_adjust + top_adjust;
3377 const float H = glyph->
maxy - glyph->
miny;
3407 float commonOffset = std::numeric_limits<float>::max();
3409 int overbarDepth = -1;
3410 int braceNesting = 0;
3414 if( *chIt ==
'~' && overbarDepth == -1 )
3418 if( ++lookahead !=
end && *lookahead ==
'{' )
3421 overbarDepth = braceNesting;
3426 else if( *chIt ==
'{' )
3430 else if( *chIt ==
'}' )
3432 if( braceNesting > 0 )
3435 if( braceNesting == overbarDepth )
3445 || *chIt ==
'-' || *chIt ==
'_' )
3447 glyph = defaultGlyph;
3454 textSize.
y = std::max<float>( textSize.
y, charHeight );
3456 textSize.
y -= commonOffset;
3458 return std::make_pair( textSize, commonOffset );
3502 const int cursorSize = 80;
3509 GLboolean depthTestEnabled = glIsEnabled( GL_DEPTH_TEST );
3510 glDisable( GL_DEPTH_TEST );
3512 glActiveTexture( GL_TEXTURE0 );
3513 glDisable( GL_TEXTURE_2D );
3514 glEnable( GL_BLEND );
3515 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
3518 glColor4d( color.
r, color.
g, color.
b, color.
a );
3520 glMatrixMode( GL_PROJECTION );
3522 glTranslated( 0, 0, -0.5 );
3524 glBegin( GL_LINES );
3539 double offset1 = cy - cx;
3540 VECTOR2D pos_start( screenTopLeft.
x, screenTopLeft.
x + offset1 );
3541 VECTOR2D pos_end( screenBottomRight.
x, screenBottomRight.
x + offset1 );
3544 glVertex2d( pos_start.
x, pos_start.
y );
3545 glVertex2d( pos_end.
x, pos_end.
y );
3548 double offset2 = cy + cx;
3549 VECTOR2D neg_start( screenTopLeft.
x, offset2 - screenTopLeft.
x );
3550 VECTOR2D neg_end( screenBottomRight.
x, offset2 - screenBottomRight.
x );
3553 glVertex2d( neg_start.
x, neg_start.
y );
3554 glVertex2d( neg_end.
x, neg_end.
y );
3558 glVertex2d( cursorCenter.
x, cursorBegin.
y );
3559 glVertex2d( cursorCenter.
x, cursorEnd.
y );
3561 glVertex2d( cursorBegin.
x, cursorCenter.
y );
3562 glVertex2d( cursorEnd.
x, cursorCenter.
y );
3569 if( depthTestEnabled )
3570 glEnable( GL_DEPTH_TEST );
3576 wxASSERT_MSG(
m_groups.size() < std::numeric_limits<unsigned int>::max(),
3577 wxT(
"There are no free slots to store a group" ) );
3588 wxASSERT_MSG(
m_isContextLocked,
"This should only be called from within a locked context." );
3592 throw std::runtime_error(
"Could not create the tesselator" );
3596 int glVersion = gladLoaderLoadGL();
3598 if( glVersion == 0 )
3599 throw std::runtime_error(
"Failed to load OpenGL via loader" );
3603 const char* vendor = (
const char*) glGetString( GL_VENDOR );
3604 const char* renderer = (
const char*) glGetString( GL_RENDERER );
3605 const char* version = (
const char*) glGetString( GL_VERSION );
3608 throw std::runtime_error(
"No GL context is current (glGetString returned NULL)" );
3612 wxLogTrace(
traceGalContext, wxS(
"GL context %p ready on canvas %p: %s | %s | %s" ),
3614 wxString::FromUTF8( renderer ), wxString::FromUTF8( version ) );
3616 GLint resetStrategy = 0;
3618 if( GLAD_GL_VERSION_4_5 || GLAD_GL_ARB_robustness || GLAD_GL_KHR_robustness )
3619 glGetIntegerv( GL_RESET_NOTIFICATION_STRATEGY, &resetStrategy );
3624 if( !GLAD_GL_VERSION_2_1 )
3625 throw std::runtime_error(
"OpenGL 2.1 or higher is required!" );
3627#if defined( __LINUX__ )
3629 if( glDebugMessageCallback )
3635 if( !GLAD_GL_ARB_framebuffer_object )
3636 throw std::runtime_error(
"Framebuffer objects are not supported!" );
3639 if( !GLAD_GL_ARB_vertex_buffer_object )
3640 throw std::runtime_error(
"Vertex buffer objects are not supported!" );
3645 BUILTIN_SHADERS::glsl_kicad_vert ) )
3647 throw std::runtime_error(
"Cannot compile vertex shader!" );
3652 BUILTIN_SHADERS::glsl_kicad_frag ) )
3654 throw std::runtime_error(
"Cannot compile fragment shader!" );
3658 throw std::runtime_error(
"Cannot link the shaders!" );
3665 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
3671 throw std::runtime_error(
"Requested texture size is not supported" );
3674#if wxCHECK_VERSION( 3, 3, 3 )
3675 wxGLCanvas::SetSwapInterval( -1 );
3712 GLdouble* vertex =
static_cast<GLdouble*
>( aVertexPtr );
3716 assert( vboManager );
3717 vboManager->
Vertex( vertex[0], vertex[1], vertex[2] );
3722 GLdouble** dataOut,
void* aData )
3724 GLdouble* vertex =
new GLdouble[3];
3730 param->
intersectPoints.emplace_back( vertex, std::default_delete<GLdouble[]>() );
3732 memcpy( vertex, coords, 3 *
sizeof( GLdouble ) );
3753#if defined( _MSC_VER )
3754#pragma warning( push )
3755#pragma warning( disable : 4191 )
3761#if defined( _MSC_VER )
3762#pragma warning( pop )
3777 return ( ceil( f / r ) - 0.5 ) * r;
3810 outlineGlyph.Triangulate(
3825 if( aGlyphs.empty() )
3828 bool allGlyphsAreStroke =
true;
3829 bool allGlyphsAreOutline =
true;
3831 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
3833 if( !glyph->IsStroke() )
3835 allGlyphsAreStroke =
false;
3840 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
3842 if( !glyph->IsOutline() )
3844 allGlyphsAreOutline =
false;
3849 if( allGlyphsAreStroke )
3852 int lineQuadCount = 0;
3854 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
3858 for(
const std::vector<VECTOR2D>& points : strokeGlyph )
3859 lineQuadCount += points.size() - 1;
3864 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
3868 for(
const std::vector<VECTOR2D>& points : strokeGlyph )
3875 points.size(),
false );
3881 else if( allGlyphsAreOutline )
3884 int triangleCount = 0;
3886 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
3890 for(
unsigned int i = 0; i < outlineGlyph.TriangulatedPolyCount(); i++ )
3893 outlineGlyph.TriangulatedPolygon( i );
3904 for(
const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
3908 for(
unsigned int i = 0; i < outlineGlyph.TriangulatedPolyCount(); i++ )
3911 outlineGlyph.TriangulatedPolygon( i );
3928 for(
size_t i = 0; i < aGlyphs.size(); i++ )
3929 DrawGlyph( *aGlyphs[i], i, aGlyphs.size() );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
void SetOpenGLInfo(const char *aVendor, const char *aRenderer, const char *aVersion)
A setter for OpenGL info when it's initialized.
void SetOpenGLBackendInfo(wxString aBackend)
A setter for OpenGL backend info after the canvas is created.
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Bezier curves to polygon converter.
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
This class handle bitmap images in KiCad.
const wxImage * GetOriginalImageData() const
VECTOR2I GetSizePixels() const
EDA_ANGLE Rotation() const
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr const Vec GetEnd() const
constexpr coord_type GetLeft() const
constexpr const Vec & GetOrigin() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
static const WX_CURSOR_TYPE GetCursor(KICURSOR aCursorType, bool aHiDPI=false)
Get a cursor bundle (wx 3.3+) or appropriate cursor (older versions)
void UnlockCtx(wxGLContext *aContext)
Allow other canvases to bind an OpenGL context.
void DestroyCtx(wxGLContext *aContext)
Destroy a managed OpenGL context.
bool LockCtx(wxGLContext *aContext, wxGLCanvas *aCanvas)
Set a context as current and prevents other canvases from switching it.
wxGLContext * CreateCtx(wxGLCanvas *aCanvas, const wxGLContext *aOther=nullptr)
Create a managed OpenGL context.
static int SetSwapInterval(wxGLCanvas *aCanvas, int aVal)
Attempt to set the OpenGL swap interval.
static wxString DetectGLBackend(wxGLCanvas *aCanvas)
HIDPI_GL_CANVAS(const KIGFX::VC_SETTINGS &aSettings, wxWindow *aParent, const wxGLAttributes &aGLAttribs, wxWindowID aId=wxID_ANY, const wxPoint &aPos=wxDefaultPosition, const wxSize &aSize=wxDefaultSize, long aStyle=0, const wxString &aName=wxGLCanvasName, const wxPalette &aPalette=wxNullPalette)
virtual wxSize GetNativePixelSize() const
double GetScaleFactor() const
Get the current scale factor.
virtual bool IsStroke() const
virtual bool IsOutline() const
A color representation with 4 components: red, green, blue, alpha.
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
COLOR4D & Brighten(double aFactor)
Makes the color brighter by a given factor.
static const COLOR4D BLACK
bool IsTextMirrored() const
void SetGridColor(const COLOR4D &aGridColor)
Set the grid color.
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
bool IsCursorEnabled() const
Return information about cursor visibility.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
friend class GAL_CONTEXT_LOCKER
MATRIX3x3D m_worldScreenMatrix
World transformation.
VECTOR2D GetVisibleGridSize() const
Return the visible grid size in x and y directions.
double m_layerDepth
The actual layer depth.
MATRIX3x3D m_screenWorldMatrix
Screen transformation.
friend class GAL_SCOPED_ATTRS
bool m_axesEnabled
Should the axes be drawn.
float m_gridLineWidth
Line width of the grid.
VECTOR2I m_screenSize
Screen size in screen (wx logical) coordinates.
GR_TEXT_H_ALIGN_T GetHorizontalJustify() const
void normalize(T &a, T &b)
Ensure that the first element is smaller than the second.
VECTOR2D m_depthRange
Range of the depth.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual bool SetNativeCursorStyle(KICURSOR aCursor, bool aHiDPI)
Set the cursor in the native panel.
GRID_STYLE m_gridStyle
Grid display style.
COLOR4D m_axesColor
Color of the axes.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
float m_lineWidth
The line width.
void computeWorldScale()
Compute the scaling factor for the world->screen matrix.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
VECTOR2D m_gridSize
The grid size.
COLOR4D getCursorColor() const
Get the actual cursor color to draw.
COLOR4D m_fillColor
The fill color.
double m_worldUnitLength
The unit length of the world coordinates [inch].
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Handle updating display options.
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
BOX2D gridScreenBBox(const GRID_SOURCE &aSrc) const
VECTOR2D m_cursorPosition
Current cursor position (world coordinates)
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
const VECTOR2I & GetGlyphSize() const
int m_gridTick
Every tick line gets the double width.
double m_worldScale
The scale factor world->screen.
VECTOR2D m_gridOrigin
The grid origin.
virtual void SetMinLineWidth(float aLineWidth)
Set the minimum line width in pixels.
KICURSOR m_currentNativeCursor
Current cursor.
bool m_globalFlipY
Flag for Y axis flipping.
float GetMinLineWidth() const
Get the minimum line width in pixels.
bool m_isFillEnabled
Is filling of graphic objects enabled ?
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
COLOR4D m_gridColor
Color of the grid.
COLOR4D m_strokeColor
The color of the outlines.
double computeMinGridSpacing() const
Compute minimum grid spacing from the grid settings.
bool m_isStrokeEnabled
Are the outlines stroked ?
std::vector< GRID_SOURCE > m_gridSources
Sources overlayed on the display grid.
GAL_DISPLAY_OPTIONS & m_options
bool m_gridVisibility
Should the grid be shown.
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
bool m_globalFlipX
Flag for X axis flipping.
GR_TEXT_V_ALIGN_T GetVerticalJustify() const
KIGFX::CROSS_HAIR_MODE m_crossHairMode
Crosshair drawing mode.
VECTOR2D m_lookAtPoint
Point to be looked at in world space.
GAL(GAL_DISPLAY_OPTIONS &aOptions)
GLuint cacheBitmap(const BITMAP_BASE *aBitmap)
const size_t m_cacheMaxElements
GLuint RequestBitmap(const BITMAP_BASE *aBitmap)
void Abandon()
Drop the cached texture names without deleting them.
std::list< GLuint > m_freedTextureIds
const size_t m_cacheMaxSize
std::map< const KIID, CACHED_BITMAP > m_bitmaps
std::list< KIID > m_cacheLru
Limit how often the OpenGL canvases are rebuilt after GPU resets.
static const unsigned int DIRECT_RENDERING
OpenGL implementation of the Graphics Abstraction Layer.
void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
void drawPolygon(GLdouble *aPoints, int aPointCount)
Draw a filled polygon.
void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Change the depth (Z-axis position) of the group.
void skipMouseEvent(wxMouseEvent &aEvent)
Skip the mouse event to the parent.
void drawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth, bool aReserve=true)
Internal method for segment drawing.
unsigned int m_groupCounter
Counter used for generating keys for groups.
void EndDiffLayer() override
Ends rendering of a differential layer.
VERTEX_MANAGER * m_overlayManager
Container for storing overlaid VERTEX_ITEMs.
void Scale(const VECTOR2D &aScale) override
Scale the context.
bool m_isInitialized
Basic initialization flag, has to be done when the window is visible.
VERTEX_MANAGER * m_currentManager
Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs).
void drawCircle(const VECTOR2D &aCenterPoint, double aRadius, bool aReserve=true)
Internal method for circle drawing.
std::deque< std::shared_ptr< GLdouble > > m_tessIntersects
void DrawEllipseArc(const VECTOR2D &aCenterPoint, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aEndAngle) override
Draw an elliptical arc in world coordinates.
void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
bool IsInitialized() const override
Return the initialization status for the canvas.
void LockContext(int aClientCookie) override
Use GAL_CONTEXT_LOCKER RAII object unless you know what you're doing.
WX_CURSOR_TYPE m_currentwxCursor
wx cursor showing the current native cursor.
unsigned int m_mainBuffer
Main rendering target.
static std::set< OPENGL_GAL * > m_instances
Canvases to repaint after a reset.
std::unique_ptr< GL_BITMAP_CACHE > m_bitmapCache
std::pair< VECTOR2D, float > computeBitmapTextSize(const UTF8 &aText) const
Compute a size of text drawn using bitmap font with current text setting applied.
void SetTarget(RENDER_TARGET aTarget) override
Set the target for rendering.
void blitCursor()
Blit cursor into the current screen.
static wxString CheckFeatures(GAL_DISPLAY_OPTIONS &aOptions)
Check OpenGL features.
void ClearTarget(RENDER_TARGET aTarget) override
Clear the target for rendering.
void drawBitmapOverbar(double aLength, double aHeight, bool aReserve=true)
Draw an overbar over the currently drawn text.
void EndGroup() override
End the group.
bool m_isBitmapFontInitialized
Is the shader set to use bitmap fonts?
static GL_RESET_BUDGET m_resetBudget
Rate of resets tolerated before falling back.
void drawSegmentChain(const std::function< VECTOR2D(int)> &aPointGetter, int aPointCount, double aWidth, bool aReserve=true)
Generic way of drawing a chain of segments stored in different containers.
void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle, double aWidth, double aMaxError) override
Draw an arc segment.
void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle) override
Draw a text using a bitmap font.
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Update handler for OpenGL settings.
unsigned int m_overlayBuffer
Auxiliary rendering target (for menus etc.)
void PostPaint(wxPaintEvent &aEvent)
Post an event to m_paintListener.
OPENGL_COMPOSITOR * m_compositor
Handles multiple rendering targets.
VERTEX_MANAGER * m_cachedManager
Container for storing cached VERTEX_ITEMs.
void Translate(const VECTOR2D &aTranslation) override
Translate the context.
static bool m_glLoaded
GL entry points are loaded, so resets can be queried.
void DrawPolyline(const std::deque< VECTOR2D > &aPointList) override
Draw a polyline.
bool SetNativeCursorStyle(KICURSOR aCursor, bool aHiDPI) override
Set the cursor in the native panel.
void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0) override
Draw a cubic bezier spline.
void drawFilledSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a filled semicircle.
void onPaint(wxPaintEvent &aEvent)
This is the OnPaint event handler.
void DrawGroup(int aGroupNumber) override
Draw the stored group.
GLint ufm_minLinePixelWidth
void Restore() override
Restore the context.
int m_ownContextGroupId
Group this canvas' contexts were created in.
bool IsResetSettled() override
Check whether the driver has finished the reset that destroyed this canvas' context.
void DrawGrid() override
Draw the grid.
void DrawSegmentChain(const std::vector< VECTOR2D > &aPointList, double aWidth) override
Draw a chain of rounded segments.
static GL_RESET_BUDGET::CLOCK::time_point m_resetDetectedAt
When the last reset was detected, to stop waiting on a driver that never reports completion.
void drawStrokedSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle, bool aReserve=true)
Draw a stroked semicircle.
unsigned int getNewGroupNumber()
Return a valid key that can be used as a new group number.
void Flush() override
Force all remaining objects to be drawn.
GLint ufm_antialiasingOffset
void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
bool IsVisible() const override
Return true if the GAL canvas is visible on the screen.
wxEvtHandler * m_mouseListener
int m_swapInterval
Used to store swap interval information.
void ClearCache() override
Delete all data created during caching of graphic items.
double getWorldPixelSize() const
void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
GROUPS_MAP m_groups
Stores information about VBO objects (groups)
void endUpdate() override
Disable item update mode.
void ClearScreen() override
Clear the screen.
void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
GLint ufm_fontTextureWidth
void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
void drawTriangulatedPolyset(const SHAPE_POLY_SET &aPoly, bool aStrokeTriangulation)
Draw a set of polygons with a cached triangulation.
void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
VERTEX_MANAGER * m_nonCachedManager
Container for storing non-cached VERTEX_ITEMs.
int drawBitmapChar(unsigned long aChar, bool aReserve=true)
Draw a single character using bitmap font.
GLUtesselator * m_tesselator
wxEvtHandler * m_paintListener
void StartDiffLayer() override
Begins rendering of a differential layer.
void drawGridCoverageShape(const GRID_SOURCE &aSrc)
Fill a source's coverage region into the current color/stencil state.
static bool m_resetSettled
Driver finished the last reset.
bool m_isContextLocked
Used for assertion checking.
void Save() override
Save the context.
void DrawHoleWall(const VECTOR2D &aCenterPoint, double aHoleRadius, double aWallWidth) override
Draw a hole wall ring.
bool m_isFramebufferInitialized
Are the framebuffers initialized?
void ComputeWorldScreenMatrix() override
Compute the world <-> screen transformation matrix.
void orphanContextGroup()
Abandon the shared context group so the next canvas created starts a fresh one.
bool Show(bool aShow) override
Shows/hides the GAL canvas.
void SetMinLineWidth(float aLineWidth) override
Set the minimum line width in pixels.
static GLuint g_fontTexture
Bitmap font texture handle (shared)
virtual bool HasTarget(RENDER_TARGET aTarget) override
Return true if the target exists.
GAL_CONTEXT_LOSS GetContextLoss() const override
Check whether a GPU reset destroyed this canvas' rendering context.
bool GetScreenshot(wxImage &aDstImage)
void reserveLineQuads(const int aLineCount)
Reserve specified number of line quads.
void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
OPENGL_GAL(const KIGFX::VC_SETTINGS &aVcSettings, GAL_DISPLAY_OPTIONS &aDisplayOptions, wxWindow *aParent, wxEvtHandler *aMouseListener=nullptr, wxEvtHandler *aPaintListener=nullptr, const wxString &aName=wxT("GLCanvas"))
void beginUpdate() override
Enable item update mode.
void DrawEllipse(const VECTOR2D &aCenterPoint, double aMajorRadius, double aMinorRadius, const EDA_ANGLE &aRotation) override
Draw a closed ellipse.
double calcAngleStep(double aRadius) const
Compute the angle step when drawing arcs/circles approximated with lines.
virtual void DrawGlyph(const KIFONT::GLYPH &aGlyph, int aNth, int aTotal) override
Draw a polygon representing a font glyph.
bool m_isGrouping
Was a group started?
void BeginDrawing() override
Start/end drawing functions, draw calls can be only made in between the calls to BeginDrawing()/EndDr...
GLint ufm_screenPixelSize
void Rotate(double aAngle) override
Rotate the context.
int BeginGroup() override
Begin a group.
GLint ufm_pixelSizeMultiplier
VECTOR2D getScreenPixelSize() const
void drawGridSources()
Render m_gridSources priority-descending; each writes its coverage into the stencil so lower-priority...
static int m_contextGroupId
Changes each time a reset kills the shared group.
void DrawBitmap(const BITMAP_BASE &aBitmap, double alphaBlend=1.0) override
Draw a bitmap image.
void drawPolyline(const std::function< VECTOR2D(int)> &aPointGetter, int aPointCount, bool aReserve=true)
Generic way of drawing a polyline stored in different containers.
bool detectContextReset()
RENDER_TARGET GetTarget() const override
Get the currently used target for rendering.
void skipGestureEvent(wxGestureEvent &aEvent)
Skip the gesture event to the parent.
void UnlockContext(int aClientCookie) override
void drawSemiCircle(const VECTOR2D &aCenterPoint, double aRadius, double aAngle)
Draw a semicircle.
void drawLineQuad(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, bool aReserve=true)
Draw a quad for the line.
VERTEX_MANAGER * m_tempManager
Container for storing temp (diff mode) VERTEX_ITEMs.
virtual void DrawGlyphs(const std::vector< std::unique_ptr< KIFONT::GLYPH > > &aGlyphs) override
Draw polygons representing font glyphs.
void onSetNativeCursor(wxSetCursorEvent &aEvent)
Give the correct cursor image when the native widget asks for it.
void EnableDepthTest(bool aEnabled=false) override
void EndDrawing() override
End the drawing, needs to be called for every new frame.
SHADER * m_shader
There is only one shader used for different objects.
void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle) override
Draw an arc.
bool m_isContextValid
Did the last lock make us current?
void DrawPolylines(const std::vector< std::vector< VECTOR2D > > &aPointLists) override
Draw multiple polylines.
RENDER_TARGET m_currentTarget
Current rendering target.
wxGLContext * m_glPrivContext
Canvas-specific OpenGL context.
void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Change the color used to draw the group.
static bool m_isBitmapFontLoaded
Is the bitmap font texture loaded?
static bool m_resetBudgetExhausted
Resets came too often to keep using OpenGL.
static wxGLContext * m_glMainContext
Parent OpenGL context.
void setupShaderParameters()
Set up the shader parameters for OpenGL rendering.
unsigned int m_tempBuffer
Temporary rendering target (for diffing etc.)
void init()
Basic OpenGL initialization and feature checks.
static int m_instanceCounter
GL GAL instance counter.
Provide the access to the OpenGL shaders.
Class to control vertex container and GPU with possibility of emulating old-style OpenGL 1....
bool Vertex(const VERTEX &aVertex)
Add a vertex with the given coordinates to the currently set item.
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
GL_CONTEXT_MANAGER * GetGLContextManager()
A small class to help profiling.
void Stop()
Save the time when this function was called, and set the counter stane to stop.
void Start()
Start or restart the counter.
double msecs(bool aSinceLast=false)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsClosed() const override
int PointCount() const
Return the number of points (vertices) in this line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
size_t GetTriangleCount() const
void GetTriangle(int index, VECTOR2I &a, VECTOR2I &b, VECTOR2I &c) const
Represent a set of closed polygons.
bool IsTriangulationUpToDate() const
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
uni_iter is a non-mutating iterator that walks through unicode code points in the UTF8 encoded string...
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
uni_iter uend() const
Return a uni_iter initialized to the end of "this" UTF8 byte sequence.
uni_iter ubegin() const
Returns a uni_iter initialized to the start of "this" UTF8 byte sequence.
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
static constexpr EDA_ANGLE FULL_CIRCLE
a few functions useful in geometry calculations.
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
const wxChar *const traceGalContext
Flag to enable debug output of GAL context binding.
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
This file contains miscellaneous commonly used macros and functions.
MATRIX3x3< double > MATRIX3x3D
const FONT_GLYPH_TYPE * LookupGlyph(unsigned int aCodepoint)
FONT_INFO_TYPE font_information
GAL_API FONT_IMAGE_TYPE font_image
The Cairo implementation of the graphics abstraction layer.
constexpr double GRID_DIM_ALPHA
Opacity of the background wash laid over a selected grid item's area, to fade the grids showing throu...
GAL_CONTEXT_LOSS
State of a canvas' rendering context after a GPU reset.
@ REPEATED
Contexts keep being lost; stop using this backend.
@ RECOVERABLE
Context was lost; rebuild the canvas.
@ SMALL_CROSS
Use small cross instead of dots for the grid.
@ DOTS
Use dots for the grid.
@ LINES
Use lines for the grid.
constexpr double GRID_SELECTED_BRIGHTEN
How far the grid being edited is lifted above its own colour.
@ SHADER_TYPE_VERTEX
Vertex shader.
@ SHADER_TYPE_FRAGMENT
Fragment shader.
double AutoSparsePitch(double aPitch, unsigned aTick, double aThreshold)
Multiply aPitch by aTick until it exceeds aThreshold, so a sub-threshold grid still shows every Nth l...
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
@ TARGET_TEMP
Temporary target for drawing in separate layer.
@ TARGET_CACHED
Main rendering target (cached)
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
constexpr double GRID_EDGE_DARKEN
How far the hairline round a grid's coverage sits below its own colour.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static const wxChar *const traceGalXorMode
static void InitTesselatorCallbacks(GLUtesselator *aTesselator)
void CALLBACK CombineCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut, void *aData)
static GLenum queryResetStatus()
void CALLBACK VertexCallback(GLvoid *aVertexPtr, void *aData)
void CALLBACK EdgeCallback(GLboolean aEdgeFlag)
static wxGLAttributes getGLAttribs()
void CALLBACK ErrorCallback(GLenum aErrorCode)
double round_to_half_pixel(double f, double r)
#define SEG_PER_CIRCLE_COUNT
The default number of points for circle approximation.
PGM_BASE & Pgm()
The global program "get" accessor.
std::vector< FAB_LAYER_COLOR > dummy
unsigned priority
Higher wins where grids overlap.
double orientation
Rotation about origin, radians CCW.
VECTOR2D extent
Cartesian: (dx, dy) = size/2 from origin.
VECTOR2D pitch
Cartesian: (dx, dy); polar: (dr, dPhi rad).
Render-time projection of a grid: GRID_GEOMETRY (kind/origin/pitch/orientation/extent) plus rendering...
unsigned tick
Major-tick interval (0 = inherit default).
bool axesEnabled
Skip grid lines coincident with the world axes (only meaningful for unbounded cartesian).
bool highlighted
Render with edit-mode emphasis (selected grid).
bool unbounded
No extent; visible range derived from screen corners.
Parameters passed to the GLU tesselator.
VERTEX_MANAGER * vboManager
Manager used for storing new vertices.
std::deque< std::shared_ptr< GLdouble > > & intersectPoints
Intersect points, that have to be freed after tessellation.
Structure to keep VIEW_CONTROLS settings for easy store/restore operations.
@ GR_TEXT_H_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_INDETERMINATE
wxLogTrace helper definitions.
void enableGlDebug(bool aEnable)
Enable or disable OpenGL driver messages output.
int checkGlError(const std::string &aInfo, const char *aFile, int aLine, bool aThrow)
Check if a recent OpenGL operation has failed.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR2I ToVECTOR2I(const wxSize &aSize)