diff --git a/common/font/font.cpp b/common/font/font.cpp index 785a5d20d4..cad75aafa1 100644 --- a/common/font/font.cpp +++ b/common/font/font.cpp @@ -264,8 +264,7 @@ void FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const wxSt (void) drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin, textStyle ); - for( const std::unique_ptr& glyph : glyphs ) - aGal->DrawGlyph( *glyph.get() ); + aGal->DrawGlyphs( glyphs ); } diff --git a/common/font/glyph.cpp b/common/font/glyph.cpp index 2653dfcb29..1982638846 100644 --- a/common/font/glyph.cpp +++ b/common/font/glyph.cpp @@ -27,6 +27,8 @@ using namespace KIFONT; STROKE_GLYPH::STROKE_GLYPH( const STROKE_GLYPH& aGlyph ) { + reserve( aGlyph.size() ); + for( const std::vector& pointList : aGlyph ) push_back( pointList ); diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index e6701a1549..515a289a1a 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -234,6 +234,25 @@ void CAIRO_GAL_BASE::syncLineWidth( bool aForceWidth, double aWidth ) } +void CAIRO_GAL_BASE::DrawSegmentChain( const std::vector& aPointList, double aWidth ) +{ + for( size_t i = 0; i + 1 < aPointList.size(); ++i ) + DrawSegment( aPointList[i], aPointList[i + 1], aWidth ); +} + + +void CAIRO_GAL_BASE::DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ) +{ + int numPoints = aLineChain.PointCount(); + + if( aLineChain.IsClosed() ) + numPoints += 1; + + for( int i = 0; i + 1 < numPoints; ++i ) + DrawSegment( aLineChain.CPoint( i ), aLineChain.CPoint( i + 1 ), aWidth ); +} + + void CAIRO_GAL_BASE::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) { diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index a17fe064ee..e9552e47ab 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -719,6 +719,13 @@ void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoin void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) +{ + drawSegment( aStartPoint, aEndPoint, aWidth ); +} + + +void OPENGL_GAL::drawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth, + bool aReserve ) { VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineLength = startEndVector.EuclideanNorm(); @@ -733,7 +740,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP // segments. In this case, we need to draw a circle for the minimal segment. if( startx == endx || starty == endy ) { - DrawCircle( aStartPoint, aWidth / 2 ); + drawCircle( aStartPoint, aWidth / 2, aReserve ); return; } @@ -742,7 +749,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP m_currentManager->Color( m_fillColor.r, m_fillColor.g, m_fillColor.b, m_fillColor.a ); SetLineWidth( aWidth ); - drawLineQuad( aStartPoint, aEndPoint ); + drawLineQuad( aStartPoint, aEndPoint, aReserve ); } else { @@ -755,16 +762,20 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP Save(); + if( aReserve ) + m_currentManager->Reserve( 6 + 6 + 3 + 3 ); // Two line quads and two semicircles + m_currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 ); m_currentManager->Rotate( lineAngle.AsRadians(), 0.0f, 0.0f, 1.0f ); - drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ), VECTOR2D( lineLength, aWidth / 2.0 ) ); + drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ), VECTOR2D( lineLength, aWidth / 2.0 ), false ); - drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ), VECTOR2D( lineLength, -aWidth / 2.0 ) ); + drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ), VECTOR2D( lineLength, -aWidth / 2.0 ), + false ); // Draw line caps - drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 ); - drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 ); + drawStrokedSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2, false ); + drawStrokedSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2, false ); Restore(); } @@ -772,10 +783,18 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) +{ + drawCircle( aCenterPoint, aRadius ); +} + + +void OPENGL_GAL::drawCircle( const VECTOR2D& aCenterPoint, double aRadius, bool aReserve ) { if( m_isFillEnabled ) { - m_currentManager->Reserve( 3 ); + if( aReserve ) + m_currentManager->Reserve( 3 ); + m_currentManager->Color( m_fillColor.r, m_fillColor.g, m_fillColor.b, m_fillColor.a ); /* Draw a triangle that contains the circle, then shade it leaving only the circle. @@ -799,7 +818,9 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) } if( m_isStrokeEnabled ) { - m_currentManager->Reserve( 3 ); + if( aReserve ) + m_currentManager->Reserve( 3 ); + m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b, m_strokeColor.a ); @@ -994,10 +1015,25 @@ void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, VECTOR2D p( cos( startAngle ) * aRadius, sin( startAngle ) * aRadius ); double alpha; + int lineCount = 0; + + for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement ) + { + lineCount++; + } + + // The last missing part + if( alpha != endAngle ) + { + lineCount++; + } + + reserveLineQuads( lineCount ); + for( alpha = startAngle + alphaIncrement; alpha <= endAngle; alpha += alphaIncrement ) { VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius ); - DrawLine( p, p_next ); + drawLineQuad( p, p_next, false ); p = p_next; } @@ -1006,7 +1042,7 @@ void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, if( alpha != endAngle ) { VECTOR2D p_last( cos( endAngle ) * aRadius, sin( endAngle ) * aRadius ); - DrawLine( p, p_last ); + drawLineQuad( p, p_last, false ); } } @@ -1053,6 +1089,33 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn } +void OPENGL_GAL::DrawSegmentChain( const std::vector& aPointList, double aWidth ) +{ + drawSegmentChain( + [&]( int idx ) + { + return aPointList[idx]; + }, + aPointList.size(), aWidth ); +} + + +void OPENGL_GAL::DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ) +{ + auto numPoints = aLineChain.PointCount(); + + if( aLineChain.IsClosed() ) + numPoints += 1; + + drawSegmentChain( + [&]( int idx ) + { + return aLineChain.CPoint( idx ); + }, + numPoints, aWidth ); +} + + void OPENGL_GAL::DrawPolyline( const std::deque& aPointList ) { drawPolyline( @@ -1102,6 +1165,27 @@ void OPENGL_GAL::DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) } +void OPENGL_GAL::DrawPolylines( const std::vector>& aPointList ) +{ + int lineQuadCount = 0; + + for( const std::vector& points : aPointList ) + lineQuadCount += points.size() - 1; + + reserveLineQuads( lineQuadCount ); + + for( const std::vector& points : aPointList ) + { + drawPolyline( + [&]( int idx ) + { + return points[idx]; + }, + points.size(), false ); + } +} + + void OPENGL_GAL::DrawPolygon( const std::deque& aPointList ) { wxCHECK( aPointList.size() >= 2, /* void */ ); @@ -1146,6 +1230,17 @@ void OPENGL_GAL::drawTriangulatedPolyset( const SHAPE_POLY_SET& aPolySet, if( m_isFillEnabled ) { + int totalTriangleCount = 0; + + for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j ) + { + auto triPoly = aPolySet.TriangulatedPolygon( j ); + + totalTriangleCount += triPoly->GetTriangleCount(); + } + + m_currentManager->Reserve( 3 * totalTriangleCount ); + for( unsigned int j = 0; j < aPolySet.TriangulatedPolyCount(); ++j ) { auto triPoly = aPolySet.TriangulatedPolygon( j ); @@ -1333,7 +1428,6 @@ void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2I& aPosition, std::tie( textSize, commonOffset ) = computeBitmapTextSize( text ); const double SCALE = 1.4 * GetGlyphSize().y / textSize.y; - int overbarLength = 0; double overbarHeight = textSize.y; Save(); @@ -1381,49 +1475,91 @@ void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2I& aPosition, break; } + int overbarLength = 0; int overbarDepth = -1; int braceNesting = 0; - for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt ) + auto iterateString = + [&]( std::function overbarFn, + std::function bitmapCharFn ) { - wxASSERT_MSG( *chIt != '\n' && *chIt != '\r', "No support for multiline bitmap text yet" ); - - if( *chIt == '~' && overbarDepth == -1 ) + for( UTF8::uni_iter chIt = text.ubegin(), end = text.uend(); chIt < end; ++chIt ) { - UTF8::uni_iter lookahead = chIt; + wxASSERT_MSG( *chIt != '\n' && *chIt != '\r', + "No support for multiline bitmap text yet" ); - if( ++lookahead != end && *lookahead == '{' ) + if( *chIt == '~' && overbarDepth == -1 ) + { + UTF8::uni_iter lookahead = chIt; + + if( ++lookahead != end && *lookahead == '{' ) + { + chIt = lookahead; + overbarDepth = braceNesting; + braceNesting++; + continue; + } + } + else if( *chIt == '{' ) { - chIt = lookahead; - overbarDepth = braceNesting; braceNesting++; - continue; } - } - else if( *chIt == '{' ) - { - braceNesting++; - } - else if( *chIt == '}' ) - { - if( braceNesting > 0 ) - braceNesting--; - - if( braceNesting == overbarDepth ) + else if( *chIt == '}' ) { - drawBitmapOverbar( overbarLength, overbarHeight ); - overbarLength = 0; + if( braceNesting > 0 ) + braceNesting--; - overbarDepth = -1; - continue; + if( braceNesting == overbarDepth ) + { + overbarFn( overbarLength, overbarHeight ); + overbarLength = 0; + + overbarDepth = -1; + continue; + } } - } - if( overbarDepth != -1 ) - overbarLength += drawBitmapChar( *chIt ); - else - drawBitmapChar( *chIt ); - } + if( overbarDepth != -1 ) + overbarLength += bitmapCharFn( *chIt ); + else + bitmapCharFn( *chIt ); + } + }; + + // First, calculate the amount of characters and overbars to reserve + + int charsCount = 0; + int overbarsCount = 0; + + iterateString( + [&overbarsCount]( int aOverbarLength, int aOverbarHeight ) + { + overbarsCount++; + }, + [&charsCount]( unsigned long aChar ) -> int + { + if( aChar != ' ' ) + charsCount++; + + return 0; + } ); + + m_currentManager->Reserve( 6 * charsCount + 6 * overbarsCount ); + + // Now reset the state and actually draw the characters and overbars + overbarLength = 0; + overbarDepth = -1; + braceNesting = 0; + + iterateString( + [&]( int aOverbarLength, int aOverbarHeight ) + { + drawBitmapOverbar( aOverbarLength, aOverbarHeight, false ); + }, + [&]( unsigned long aChar ) -> int + { + return drawBitmapChar( aChar, false ); + } ); // Handle the case when overbar is active till the end of the drawn text m_currentManager->Translate( 0, commonOffset, 0 ); @@ -1864,7 +2000,8 @@ void OPENGL_GAL::DrawCursor( const VECTOR2D& aCursorPosition ) } -void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) +void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, + const bool aReserve ) { /* Helper drawing: ____--- v3 ^ * ____---- ... \ \ @@ -1888,7 +2025,8 @@ void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd VECTOR2D vs( v2.x - v1.x, v2.y - v1.y ); - m_currentManager->Reserve( 6 ); + if( aReserve ) + reserveLineQuads( 1 ); // Line width is maintained by the vertex shader m_currentManager->Shader( SHADER_LINE_A, m_lineWidth, vs.x, vs.y ); @@ -1911,6 +2049,12 @@ void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd } +void OPENGL_GAL::reserveLineQuads( const int aLineCount ) +{ + m_currentManager->Reserve( 6 * aLineCount ); +} + + void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ) { if( m_isFillEnabled ) @@ -1958,14 +2102,16 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad } -void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, - double aAngle ) +void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle, + bool aReserve ) { double outerRadius = aRadius + ( m_lineWidth / 2 ); Save(); - m_currentManager->Reserve( 3 ); + if( aReserve ) + m_currentManager->Reserve( 3 ); + m_currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f ); m_currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); @@ -2032,24 +2178,81 @@ void OPENGL_GAL::drawPolygon( GLdouble* aPoints, int aPointCount ) } -void OPENGL_GAL::drawPolyline( const std::function& aPointGetter, int aPointCount ) +void OPENGL_GAL::drawPolyline( const std::function& aPointGetter, int aPointCount, + bool aReserve ) { wxCHECK( aPointCount >= 2, /* return */ ); m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b, m_strokeColor.a ); - int i; - for( i = 1; i < aPointCount; ++i ) + if( aReserve ) + { + reserveLineQuads( aPointCount - 1 ); + } + + for( int i = 1; i < aPointCount; ++i ) { auto start = aPointGetter( i - 1 ); auto end = aPointGetter( i ); - drawLineQuad( start, end ); + drawLineQuad( start, end, false ); } } -int OPENGL_GAL::drawBitmapChar( unsigned long aChar ) +void OPENGL_GAL::drawSegmentChain( const std::function& aPointGetter, + int aPointCount, double aWidth, bool aReserve ) +{ + wxCHECK( aPointCount >= 2, /* return */ ); + + m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b, m_strokeColor.a ); + + int vertices = 0; + + for( int i = 1; i < aPointCount; ++i ) + { + auto start = aPointGetter( i - 1 ); + auto end = aPointGetter( i ); + + VECTOR2D startEndVector = start - end; + double lineLength = startEndVector.EuclideanNorm(); + + float startx = start.x; + float starty = end.y; + float endx = start.x + lineLength; + float endy = end.y + lineLength; + + // Be careful about floating point rounding. As we draw segments in larger and larger + // coordinates, the shader (which uses floats) will lose precision and stop drawing small + // segments. In this case, we need to draw a circle for the minimal segment. + if( startx == endx || starty == endy ) + { + vertices += 3; // One circle + } + + if( m_isFillEnabled || aWidth == 1.0 ) + { + vertices += 6; // One line + } + else + { + vertices += 6 + 6 + 3 + 3; // Two lines and two half-circles + } + } + + m_currentManager->Reserve( vertices ); + + for( int i = 1; i < aPointCount; ++i ) + { + auto start = aPointGetter( i - 1 ); + auto end = aPointGetter( i ); + + drawSegment( start, end, aWidth, false ); + } +} + + +int OPENGL_GAL::drawBitmapChar( unsigned long aChar, bool aReserve ) { const float TEX_X = font_image.width; const float TEX_Y = font_image.height; @@ -2090,7 +2293,9 @@ int OPENGL_GAL::drawBitmapChar( unsigned long aChar ) const float H = glyph->atlas_h - font_information.smooth_pixels * 2; const float B = 0; - m_currentManager->Reserve( 6 ); + if( aReserve ) + m_currentManager->Reserve( 6 ); + Translate( VECTOR2D( XOFF, YOFF ) ); /* Glyph: @@ -2126,7 +2331,7 @@ int OPENGL_GAL::drawBitmapChar( unsigned long aChar ) } -void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight ) +void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight, bool aReserve ) { // To draw an overbar, simply draw an overbar const FONT_GLYPH_TYPE* glyph = LookupGlyph( '_' ); @@ -2138,7 +2343,9 @@ void OPENGL_GAL::drawBitmapOverbar( double aLength, double aHeight ) Translate( VECTOR2D( -aLength, -aHeight ) ); - m_currentManager->Reserve( 6 ); + if( aReserve ) + m_currentManager->Reserve( 6 ); + m_currentManager->Color( m_strokeColor.r, m_strokeColor.g, m_strokeColor.b, m_strokeColor.a ); m_currentManager->Shader( 0 ); @@ -2452,8 +2659,7 @@ void OPENGL_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) { const auto& strokeGlyph = static_cast( aGlyph ); - for( const std::vector& pointList : strokeGlyph ) - DrawPolyline( pointList ); + DrawPolylines( strokeGlyph ); } else if( aGlyph.IsOutline() ) { @@ -2465,9 +2671,124 @@ void OPENGL_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) outlineGlyph.Triangulate( [&]( const VECTOR2D& aPt1, const VECTOR2D& aPt2, const VECTOR2D& aPt3 ) { + m_currentManager->Reserve( 3 ); + m_currentManager->Vertex( aPt1.x, aPt1.y, m_layerDepth ); m_currentManager->Vertex( aPt2.x, aPt2.y, m_layerDepth ); m_currentManager->Vertex( aPt3.x, aPt3.y, m_layerDepth ); } ); } } + + +void OPENGL_GAL::DrawGlyphs( const std::vector>& aGlyphs ) +{ + bool allGlyphsAreStroke = true; + bool allGlyphsAreOutline = true; + + for( const std::unique_ptr& glyph : aGlyphs ) + { + if( !glyph->IsStroke() ) + { + allGlyphsAreStroke = false; + break; + } + } + + for( const std::unique_ptr& glyph : aGlyphs ) + { + if( !glyph->IsOutline() ) + { + allGlyphsAreOutline = false; + break; + } + } + + if( allGlyphsAreStroke ) + { + // Optimized path for stroke fonts that pre-reserves line quads. + int lineQuadCount = 0; + + for( const std::unique_ptr& glyph : aGlyphs ) + { + const auto& strokeGlyph = static_cast( *glyph ); + + for( const std::vector& points : strokeGlyph ) + lineQuadCount += points.size() - 1; + } + + reserveLineQuads( lineQuadCount ); + + for( const std::unique_ptr& glyph : aGlyphs ) + { + const auto& strokeGlyph = static_cast( *glyph ); + + for( const std::vector& points : strokeGlyph ) + { + drawPolyline( + [&]( int idx ) + { + return points[idx]; + }, + points.size(), false ); + } + } + + return; + } + else if( allGlyphsAreOutline ) + { + // Optimized path for stroke fonts that pre-reserves glyph triangles. + int triangleCount = 0; + + for( const std::unique_ptr& glyph : aGlyphs ) + { + const auto& outlineGlyph = static_cast( *glyph ); + + // Only call CacheTriangulation if it has never been done before. Otherwise we'll hash + // the triangulation to see if it has been edited, and glyphs after creation are read-only. + if( outlineGlyph.TriangulatedPolyCount() == 0 ) + const_cast( outlineGlyph ).CacheTriangulation( false ); + + for( unsigned int i = 0; i < outlineGlyph.TriangulatedPolyCount(); i++ ) + { + const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = + outlineGlyph.TriangulatedPolygon( i ); + + triangleCount += polygon->GetTriangleCount(); + } + } + + m_currentManager->Shader( SHADER_NONE ); + m_currentManager->Color( m_fillColor ); + + m_currentManager->Reserve( 3 * triangleCount ); + + for( const std::unique_ptr& glyph : aGlyphs ) + { + const auto& outlineGlyph = static_cast( *glyph ); + + for( unsigned int i = 0; i < outlineGlyph.TriangulatedPolyCount(); i++ ) + { + const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = + outlineGlyph.TriangulatedPolygon( i ); + + for( size_t j = 0; j < polygon->GetTriangleCount(); j++ ) + { + VECTOR2I a, b, c; + polygon->GetTriangle( j, a, b, c ); + + m_currentManager->Vertex( a.x, a.y, m_layerDepth ); + m_currentManager->Vertex( b.x, b.y, m_layerDepth ); + m_currentManager->Vertex( c.x, c.y, m_layerDepth ); + } + } + } + } + else + { + // Regular path + for( size_t i = 0; i < aGlyphs.size(); i++ ) + DrawGlyph( *aGlyphs[i], i, aGlyphs.size() ); + } +} diff --git a/common/gal/opengl/vertex_manager.cpp b/common/gal/opengl/vertex_manager.cpp index 6e7baddfb2..09b3fb78b2 100644 --- a/common/gal/opengl/vertex_manager.cpp +++ b/common/gal/opengl/vertex_manager.cpp @@ -111,17 +111,17 @@ bool VERTEX_MANAGER::Vertex( GLfloat aX, GLfloat aY, GLfloat aZ ) else { newVertex = m_container->Allocate( 1 ); - } - if( newVertex == nullptr ) - { - if( show_err ) + if( newVertex == nullptr ) { - DisplayError( nullptr, wxT( "VERTEX_MANAGER::Vertex: Vertex allocation error" ) ); - show_err = false; - } + if( show_err ) + { + DisplayError( nullptr, wxT( "VERTEX_MANAGER::Vertex: Vertex allocation error" ) ); + show_err = false; + } - return false; + return false; + } } putVertex( *newVertex, aX, aY, aZ ); diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index 5e484ed6cf..c16ad58d53 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -90,6 +90,10 @@ public: /// @copydoc GAL::DrawRectangle() void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override; + /// @copydoc GAL::DrawSegmentChain() + void DrawSegmentChain( const std::vector& aPointList, double aWidth ) override; + void DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ) override; + /// @copydoc GAL::DrawPolyline() void DrawPolyline( const std::deque& aPointList ) override { drawPoly( aPointList ); } void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override @@ -99,6 +103,13 @@ public: void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) override { drawPoly( aLineChain ); } + /// @copydoc GAL::DrawPolylines() + void DrawPolylines( const std::vector>& aPointLists ) override + { + for( const std::vector& points : aPointLists ) + drawPoly( points ); + } + /// @copydoc GAL::DrawPolygon() void DrawPolygon( const std::deque& aPointList ) override { drawPoly( aPointList ); } void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) override @@ -112,6 +123,13 @@ public: /// @copydoc GAL::DrawGlyph() void DrawGlyph( const KIFONT::GLYPH& aPolySet, int aNth, int aTotal ) override; + /// @copydoc GAL::DrawGlyphs() + void DrawGlyphs( const std::vector>& aGlyphs ) override + { + for( size_t i = 0; i < aGlyphs.size(); i++ ) + DrawGlyph( *aGlyphs[i], i, aGlyphs.size() ); + } + /// @copydoc GAL::DrawCurve() void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA, const VECTOR2D& controlPointB, const VECTOR2D& endPoint, diff --git a/include/gal/graphics_abstraction_layer.h b/include/gal/graphics_abstraction_layer.h index 398845bbba..021ea69710 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -106,7 +106,16 @@ public: * @param aWidth is a width of the segment */ virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, - double aWidth ) {}; + double aWidth ){}; + + /** + * Draw a chain of rounded segments. + * + * @param aPointList is a list of 2D-Vectors containing the chain points. + * @param aWidth is a width of the segments + */ + virtual void DrawSegmentChain( const std::vector& aPointList, double aWidth ){}; + virtual void DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ){}; /** * Draw a polyline @@ -118,6 +127,13 @@ public: virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) {}; virtual void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) {}; + /** + * Draw multiple polylines + * + * @param aPointLists are lists of 2D-Vectors containing the polyline points. + */ + virtual void DrawPolylines( const std::vector>& aPointLists ){}; + /** * Draw a circle using world coordinates. * @@ -173,10 +189,15 @@ public: } /** - * Draw a polygon representing an outline font glyph. + * Draw a polygon representing a font glyph. */ virtual void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth = 0, int aTotal = 1 ) {}; + /** + * Draw polygons representing font glyphs. + */ + virtual void DrawGlyphs( const std::vector>& aGlyphs ) {}; + /** * Draw a polygon. * diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 68d0ce16aa..38f5d3df01 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -122,6 +122,10 @@ public: void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) override; + /// @copydoc GAL::DrawSegmentChain() + void DrawSegmentChain( const std::vector& aPointList, double aWidth ) override; + void DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ) override; + /// @copydoc GAL::DrawCircle() void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) override; @@ -142,6 +146,9 @@ public: void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override; void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) override; + /// @copydoc GAL::DrawPolylines() + void DrawPolylines( const std::vector>& aPointLists ) override; + /// @copydoc GAL::DrawPolygon() void DrawPolygon( const std::deque& aPointList ) override; void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) override; @@ -151,6 +158,9 @@ public: /// @copydoc GAL::DrawGlyph() virtual void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) override; + /// @copydoc GAL::DrawGlyphs() + virtual void DrawGlyphs( const std::vector>& aGlyphs ) override; + /// @copydoc GAL::DrawCurve() void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA, const VECTOR2D& controlPointB, const VECTOR2D& endPoint, @@ -382,8 +392,18 @@ private: * * @param aStartPoint is the start point of the line. * @param aEndPoint is the end point of the line. + * @param aReserve if set to false, call reserveLineQuads beforehand + * to reserve the right amount of vertices. */ - void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ); + void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, + bool aReserve = true ); + + /** + * @brief Reserves specified number of line quads. + * + * @param aLineCount the number of line quads to reserve. + */ + void reserveLineQuads( const int aLineCount ); /** * Draw a semicircle. @@ -414,17 +434,44 @@ private: * @param aCenterPoint is the center point. * @param aRadius is the radius of the semicircle. * @param aAngle is the angle of the semicircle. + * @param aReserve if set to false, reserve 3 vertices for each semicircle. * */ - void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ); + void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle, + bool aReserve = true ); + + /** + * Internal method for circle drawing. + * + * @param aReserve if set to false, reserve 3 vertices for each circle. + */ + void drawCircle( const VECTOR2D& aCenterPoint, double aRadius, bool aReserve = true ); /** * Generic way of drawing a polyline stored in different containers. * * @param aPointGetter is a function to obtain coordinates of n-th vertex. * @param aPointCount is the number of points to be drawn. + * @param aReserve if set to false, reserve aPointCount - 1 line quads. */ - void drawPolyline( const std::function& aPointGetter, int aPointCount ); + void drawPolyline( const std::function& aPointGetter, int aPointCount, + bool aReserve = true ); + + /** + * Generic way of drawing a chain of segments stored in different containers. + * + * @param aPointGetter is a function to obtain coordinates of n-th vertex. + * @param aPointCount is the number of points to be drawn. + * @param aReserve if set to false, do not reserve vertices internally. + */ + void drawSegmentChain( const std::function& aPointGetter, int aPointCount, + double aWidth, bool aReserve = true ); + + /** + * Internal method for segment drawing + */ + void drawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth, + bool aReserve = true ); /** * Draw a filled polygon. It does not need the last point to have the same coordinates @@ -443,7 +490,6 @@ private: */ void drawTriangulatedPolyset( const SHAPE_POLY_SET& aPoly, bool aStrokeTriangulation ); - /** * Draw a single character using bitmap font. * @@ -451,8 +497,9 @@ private: * * @param aChar is the character to be drawn. * @return Width of the drawn glyph. + * @param aReserve if set to false, reserve 6 vertices for each character. */ - int drawBitmapChar( unsigned long aChar ); + int drawBitmapChar( unsigned long aChar, bool aReserve = true ); /** * Draw an overbar over the currently drawn text. @@ -463,8 +510,9 @@ private: * * @param aLength is the width of the overbar. * @param aHeight is the height for the overbar. + * @param aReserve if set to false, reserve 6 vertices for each overbar. */ - void drawBitmapOverbar( double aLength, double aHeight ); + void drawBitmapOverbar( double aLength, double aHeight, bool aReserve = true ); /** * Compute a size of text drawn using bitmap font with current text setting applied. diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index ed8766b0cd..342876d2c5 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -1629,11 +1629,7 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer ) if( outline_mode ) { - for( int ii = 0; ii < shape.Outline( 0 ).SegmentCount(); ++ii ) - { - SEG seg = shape.Outline( 0 ).Segment( ii ); - m_gal->DrawSegment( seg.A, seg.B, thickness ); - } + m_gal->DrawSegmentChain( shape.Outline( 0 ), thickness ); } else { @@ -1642,11 +1638,7 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer ) if( thickness > 0 ) { - for( int ii = 0; ii < shape.Outline( 0 ).SegmentCount(); ++ii ) - { - SEG seg = shape.Outline( 0 ).Segment( ii ); - m_gal->DrawSegment( seg.A, seg.B, thickness ); - } + m_gal->DrawSegmentChain( shape.Outline( 0 ), thickness ); } if( aShape->IsFilled() ) @@ -1682,8 +1674,7 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer ) BEZIER_POLY converter( pointCtrl ); converter.GetPoly( output, thickness ); - for( unsigned ii = 0; ii + 1 < output.size(); ++ii ) - m_gal->DrawSegment( output[ii], output[ii+1], thickness ); + m_gal->DrawSegmentChain( output, thickness ); } else { @@ -1867,8 +1858,7 @@ void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer ) if( cache ) { - for( const std::unique_ptr& glyph : *cache ) - m_gal->DrawGlyph( *glyph.get() ); + m_gal->DrawGlyphs( *cache ); } else { @@ -1953,8 +1943,7 @@ void PCB_PAINTER::draw( const PCB_TEXTBOX* aTextBox, int aLayer ) if( cache ) { - for( const std::unique_ptr& glyph : *cache ) - m_gal->DrawGlyph( *glyph.get() ); + m_gal->DrawGlyphs( *cache ); } else { @@ -2022,8 +2011,7 @@ void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer ) if( cache ) { - for( const std::unique_ptr& glyph : *cache ) - m_gal->DrawGlyph( *glyph.get() ); + m_gal->DrawGlyphs( *cache ); } else { @@ -2092,8 +2080,7 @@ void PCB_PAINTER::draw( const FP_TEXTBOX* aTextBox, int aLayer ) if( cache ) { - for( const std::unique_ptr& glyph : *cache ) - m_gal->DrawGlyph( *glyph.get() ); + m_gal->DrawGlyphs( *cache ); } else {