GAL: Do better job at reserving vertices.

This commit is contained in:
dsa-t 2022-09-14 16:07:47 +00:00 committed by Seth Hillbrand
parent 397a93029e
commit bd8b737c44
9 changed files with 509 additions and 94 deletions

View File

@ -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>& glyph : glyphs )
aGal->DrawGlyph( *glyph.get() );
aGal->DrawGlyphs( glyphs );
}

View File

@ -27,6 +27,8 @@ using namespace KIFONT;
STROKE_GLYPH::STROKE_GLYPH( const STROKE_GLYPH& aGlyph )
{
reserve( aGlyph.size() );
for( const std::vector<VECTOR2D>& pointList : aGlyph )
push_back( pointList );

View File

@ -234,6 +234,25 @@ void CAIRO_GAL_BASE::syncLineWidth( bool aForceWidth, double aWidth )
}
void CAIRO_GAL_BASE::DrawSegmentChain( const std::vector<VECTOR2D>& 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 )
{

View File

@ -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<VECTOR2D>& 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<VECTOR2D>& aPointList )
{
drawPolyline(
@ -1102,6 +1165,27 @@ void OPENGL_GAL::DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain )
}
void OPENGL_GAL::DrawPolylines( const std::vector<std::vector<VECTOR2D>>& aPointList )
{
int lineQuadCount = 0;
for( const std::vector<VECTOR2D>& points : aPointList )
lineQuadCount += points.size() - 1;
reserveLineQuads( lineQuadCount );
for( const std::vector<VECTOR2D>& points : aPointList )
{
drawPolyline(
[&]( int idx )
{
return points[idx];
},
points.size(), false );
}
}
void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& 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<void( int aOverbarLength, int aOverbarHeight )> overbarFn,
std::function<int( unsigned long aChar )> 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<VECTOR2D( int )>& aPointGetter, int aPointCount )
void OPENGL_GAL::drawPolyline( const std::function<VECTOR2D( int )>& 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<VECTOR2D( int )>& 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<const KIFONT::STROKE_GLYPH&>( aGlyph );
for( const std::vector<VECTOR2D>& 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<std::unique_ptr<KIFONT::GLYPH>>& aGlyphs )
{
bool allGlyphsAreStroke = true;
bool allGlyphsAreOutline = true;
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
{
if( !glyph->IsStroke() )
{
allGlyphsAreStroke = false;
break;
}
}
for( const std::unique_ptr<KIFONT::GLYPH>& 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<KIFONT::GLYPH>& glyph : aGlyphs )
{
const auto& strokeGlyph = static_cast<const KIFONT::STROKE_GLYPH&>( *glyph );
for( const std::vector<VECTOR2D>& points : strokeGlyph )
lineQuadCount += points.size() - 1;
}
reserveLineQuads( lineQuadCount );
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
{
const auto& strokeGlyph = static_cast<const KIFONT::STROKE_GLYPH&>( *glyph );
for( const std::vector<VECTOR2D>& 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<KIFONT::GLYPH>& glyph : aGlyphs )
{
const auto& outlineGlyph = static_cast<const KIFONT::OUTLINE_GLYPH&>( *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<KIFONT::OUTLINE_GLYPH&>( 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<KIFONT::GLYPH>& glyph : aGlyphs )
{
const auto& outlineGlyph = static_cast<const KIFONT::OUTLINE_GLYPH&>( *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() );
}
}

View File

@ -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 );

View File

@ -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<VECTOR2D>& aPointList, double aWidth ) override;
void DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ) override;
/// @copydoc GAL::DrawPolyline()
void DrawPolyline( const std::deque<VECTOR2D>& 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<std::vector<VECTOR2D>>& aPointLists ) override
{
for( const std::vector<VECTOR2D>& points : aPointLists )
drawPoly( points );
}
/// @copydoc GAL::DrawPolygon()
void DrawPolygon( const std::deque<VECTOR2D>& 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<std::unique_ptr<KIFONT::GLYPH>>& 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,

View File

@ -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<VECTOR2D>& 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<std::vector<VECTOR2D>>& 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<std::unique_ptr<KIFONT::GLYPH>>& aGlyphs ) {};
/**
* Draw a polygon.
*

View File

@ -122,6 +122,10 @@ public:
void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
double aWidth ) override;
/// @copydoc GAL::DrawSegmentChain()
void DrawSegmentChain( const std::vector<VECTOR2D>& 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<std::vector<VECTOR2D>>& aPointLists ) override;
/// @copydoc GAL::DrawPolygon()
void DrawPolygon( const std::deque<VECTOR2D>& 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<std::unique_ptr<KIFONT::GLYPH>>& 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<VECTOR2D (int)>& aPointGetter, int aPointCount );
void drawPolyline( const std::function<VECTOR2D( int )>& 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<VECTOR2D( int )>& 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.

View File

@ -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<KIFONT::GLYPH>& 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<KIFONT::GLYPH>& 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<KIFONT::GLYPH>& 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<KIFONT::GLYPH>& glyph : *cache )
m_gal->DrawGlyph( *glyph.get() );
m_gal->DrawGlyphs( *cache );
}
else
{