1111#include " impeller/entity/content_context.h"
1212#include " impeller/entity/entity.h"
1313#include " impeller/geometry/path_builder.h"
14+ #include " impeller/geometry/path_component.h"
1415#include " impeller/geometry/scalar.h"
1516#include " impeller/geometry/vector.h"
1617#include " impeller/renderer/render_pass.h"
@@ -303,7 +304,8 @@ static VertexBuffer CreateSolidStrokeVertices(
303304 HostBuffer& buffer,
304305 const SolidStrokeContents::CapProc& cap_proc,
305306 const SolidStrokeContents::JoinProc& join_proc,
306- Scalar miter_limit) {
307+ Scalar miter_limit,
308+ const SmoothingApproximation& smoothing) {
307309 using VS = SolidStrokeVertexShader;
308310
309311 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
@@ -356,7 +358,8 @@ static VertexBuffer CreateSolidStrokeVertices(
356358
357359 // Generate start cap.
358360 if (!polyline.contours [contour_i].is_closed ) {
359- cap_proc (vtx_builder, polyline.points [contour_start_point_i], -normal);
361+ cap_proc (vtx_builder, polyline.points [contour_start_point_i], -normal,
362+ smoothing);
360363 }
361364
362365 // Generate contour geometry.
@@ -381,17 +384,18 @@ static VertexBuffer CreateSolidStrokeVertices(
381384
382385 // Generate join from the current line to the next line.
383386 join_proc (vtx_builder, polyline.points [point_i], previous_normal,
384- normal, miter_limit);
387+ normal, miter_limit, smoothing );
385388 }
386389 }
387390 }
388391
389392 // Generate end cap or join.
390393 if (!polyline.contours [contour_i].is_closed ) {
391- cap_proc (vtx_builder, polyline.points [contour_end_point_i - 1 ], normal);
394+ cap_proc (vtx_builder, polyline.points [contour_end_point_i - 1 ], normal,
395+ smoothing);
392396 } else {
393397 join_proc (vtx_builder, polyline.points [contour_start_point_i], normal,
394- contour_first_normal, miter_limit);
398+ contour_first_normal, miter_limit, smoothing );
395399 }
396400 }
397401
@@ -420,9 +424,9 @@ bool SolidStrokeContents::Render(const ContentContext& renderer,
420424 cmd.label = " SolidStroke" ;
421425 cmd.pipeline = renderer.GetSolidStrokePipeline (OptionsFromPass (pass));
422426 cmd.stencil_reference = entity.GetStencilDepth ();
423- cmd.BindVertices (
424- CreateSolidStrokeVertices ( entity.GetPath (), pass.GetTransientsBuffer (),
425- cap_proc_, join_proc_, miter_limit_ ));
427+ cmd.BindVertices (CreateSolidStrokeVertices (
428+ entity.GetPath (), pass.GetTransientsBuffer (), cap_proc_, join_proc_ ,
429+ miter_limit_, arc_smoothing_approximation_ ));
426430 VS::BindFrameInfo (cmd, pass.GetTransientsBuffer ().EmplaceUniform (frame_info));
427431 VS::BindStrokeInfo (cmd,
428432 pass.GetTransientsBuffer ().EmplaceUniform (stroke_info));
@@ -434,6 +438,7 @@ bool SolidStrokeContents::Render(const ContentContext& renderer,
434438
435439void SolidStrokeContents::SetStrokeSize (Scalar size) {
436440 stroke_size_ = size;
441+ arc_smoothing_approximation_ = SmoothingApproximation (5.0 / size, 0.0 , 0.0 );
437442}
438443
439444Scalar SolidStrokeContents::GetStrokeSize () const {
@@ -458,14 +463,41 @@ void SolidStrokeContents::SetStrokeCap(Cap cap) {
458463 switch (cap) {
459464 case Cap::kButt :
460465 cap_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
461- const Point& position, const Point& normal) {};
466+ const Point& position, const Point& normal,
467+ const SmoothingApproximation& smoothing) {};
462468 break ;
463469 case Cap::kRound :
464- FML_DLOG (ERROR) << " Unimplemented." ;
470+ cap_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
471+ const Point& position, const Point& normal,
472+ const SmoothingApproximation& smoothing) {
473+ SolidStrokeVertexShader::PerVertexData vtx;
474+ vtx.vertex_position = position;
475+ vtx.pen_down = 1.0 ;
476+
477+ Point forward (normal.y , -normal.x );
478+
479+ auto arc_points =
480+ CubicPathComponent (
481+ normal, normal + forward * PathBuilder::kArcApproximationMagic ,
482+ forward + normal * PathBuilder::kArcApproximationMagic , forward)
483+ .CreatePolyline (smoothing);
484+
485+ vtx.vertex_normal = normal;
486+ vtx_builder.AppendVertex (vtx);
487+ vtx.vertex_normal = -normal;
488+ vtx_builder.AppendVertex (vtx);
489+ for (const auto & point : arc_points) {
490+ vtx.vertex_normal = point;
491+ vtx_builder.AppendVertex (vtx);
492+ vtx.vertex_normal = (-point).Reflect (forward);
493+ vtx_builder.AppendVertex (vtx);
494+ }
495+ };
465496 break ;
466497 case Cap::kSquare :
467498 cap_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
468- const Point& position, const Point& normal) {
499+ const Point& position, const Point& normal,
500+ const SmoothingApproximation& smoothing) {
469501 SolidStrokeVertexShader::PerVertexData vtx;
470502 vtx.vertex_position = position;
471503 vtx.pen_down = 1.0 ;
@@ -517,22 +549,25 @@ void SolidStrokeContents::SetStrokeJoin(Join join) {
517549 case Join::kBevel :
518550 join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
519551 const Point& position, const Point& start_normal,
520- const Point& end_normal, Scalar miter_limit) {
521- CreateBevelAndGetDirection (vtx_builder, position, start_normal, end_normal);
552+ const Point& end_normal, Scalar miter_limit,
553+ const SmoothingApproximation& smoothing) {
554+ CreateBevelAndGetDirection (vtx_builder, position, start_normal,
555+ end_normal);
522556 };
523557 break ;
524558 case Join::kMiter :
525559 join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
526560 const Point& position, const Point& start_normal,
527- const Point& end_normal, Scalar miter_limit) {
561+ const Point& end_normal, Scalar miter_limit,
562+ const SmoothingApproximation& smoothing) {
528563 // 1 for no joint (straight line), 0 for max joint (180 degrees).
529564 Scalar alignment = (start_normal.Dot (end_normal) + 1 ) / 2 ;
530565 if (ScalarNearlyEqual (alignment, 1 )) {
531566 return ;
532567 }
533568
534- Scalar dir =
535- CreateBevelAndGetDirection (vtx_builder, position, start_normal, end_normal);
569+ Scalar dir = CreateBevelAndGetDirection (vtx_builder, position,
570+ start_normal, end_normal);
536571
537572 Point miter_point = (start_normal + end_normal) / 2 / alignment;
538573 if (miter_point.GetDistanceSquared ({0 , 0 }) >
@@ -549,7 +584,42 @@ void SolidStrokeContents::SetStrokeJoin(Join join) {
549584 };
550585 break ;
551586 case Join::kRound :
552- FML_DLOG (ERROR) << " Unimplemented." ;
587+ join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
588+ const Point& position, const Point& start_normal,
589+ const Point& end_normal, Scalar miter_limit,
590+ const SmoothingApproximation& smoothing) {
591+ // 0 for no joint (straight line), 1 for max joint (180 degrees).
592+ Scalar alignment = 1 - (start_normal.Dot (end_normal) + 1 ) / 2 ;
593+ if (ScalarNearlyEqual (alignment, 0 )) {
594+ return ;
595+ }
596+
597+ Scalar dir =
598+ CreateBevel (vtx_builder, position, start_normal, end_normal);
599+
600+ Point middle = (start_normal + end_normal).Normalize ();
601+ Point middle_handle = middle + Point (-middle.y , middle.x ) *
602+ PathBuilder::kArcApproximationMagic *
603+ alignment * dir;
604+ Point start_handle =
605+ start_normal + Point (start_normal.y , -start_normal.x ) *
606+ PathBuilder::kArcApproximationMagic * alignment *
607+ dir;
608+
609+ auto arc_points = CubicPathComponent (start_normal, start_handle,
610+ middle_handle, middle)
611+ .CreatePolyline (smoothing);
612+
613+ SolidStrokeVertexShader::PerVertexData vtx;
614+ vtx.vertex_position = position;
615+ vtx.pen_down = 1.0 ;
616+ for (const auto & point : arc_points) {
617+ vtx.vertex_normal = point * dir;
618+ vtx_builder.AppendVertex (vtx);
619+ vtx.vertex_normal = (-point * dir).Reflect (middle);
620+ vtx_builder.AppendVertex (vtx);
621+ }
622+ };
553623 break ;
554624 }
555625}
0 commit comments