11
11
#include " impeller/entity/content_context.h"
12
12
#include " impeller/entity/entity.h"
13
13
#include " impeller/geometry/path_builder.h"
14
+ #include " impeller/geometry/path_component.h"
14
15
#include " impeller/geometry/scalar.h"
15
16
#include " impeller/geometry/vector.h"
16
17
#include " impeller/renderer/render_pass.h"
@@ -303,7 +304,8 @@ static VertexBuffer CreateSolidStrokeVertices(
303
304
HostBuffer& buffer,
304
305
const SolidStrokeContents::CapProc& cap_proc,
305
306
const SolidStrokeContents::JoinProc& join_proc,
306
- Scalar miter_limit) {
307
+ Scalar miter_limit,
308
+ const SmoothingApproximation& smoothing) {
307
309
using VS = SolidStrokeVertexShader;
308
310
309
311
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
@@ -356,7 +358,8 @@ static VertexBuffer CreateSolidStrokeVertices(
356
358
357
359
// Generate start cap.
358
360
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);
360
363
}
361
364
362
365
// Generate contour geometry.
@@ -381,17 +384,18 @@ static VertexBuffer CreateSolidStrokeVertices(
381
384
382
385
// Generate join from the current line to the next line.
383
386
join_proc (vtx_builder, polyline.points [point_i], previous_normal,
384
- normal , miter_limit);
387
+ normal , miter_limit, smoothing );
385
388
}
386
389
}
387
390
}
388
391
389
392
// Generate end cap or join.
390
393
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);
392
396
} else {
393
397
join_proc (vtx_builder, polyline.points [contour_start_point_i], normal ,
394
- contour_first_normal, miter_limit);
398
+ contour_first_normal, miter_limit, smoothing );
395
399
}
396
400
}
397
401
@@ -420,9 +424,9 @@ bool SolidStrokeContents::Render(const ContentContext& renderer,
420
424
cmd.label = " SolidStroke" ;
421
425
cmd.pipeline = renderer.GetSolidStrokePipeline (OptionsFromPass (pass));
422
426
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_ ));
426
430
VS::BindFrameInfo (cmd, pass.GetTransientsBuffer ().EmplaceUniform (frame_info));
427
431
VS::BindStrokeInfo (cmd,
428
432
pass.GetTransientsBuffer ().EmplaceUniform (stroke_info));
@@ -434,6 +438,7 @@ bool SolidStrokeContents::Render(const ContentContext& renderer,
434
438
435
439
void SolidStrokeContents::SetStrokeSize (Scalar size) {
436
440
stroke_size_ = size;
441
+ arc_smoothing_approximation_ = SmoothingApproximation (5.0 / size, 0.0 , 0.0 );
437
442
}
438
443
439
444
Scalar SolidStrokeContents::GetStrokeSize () const {
@@ -458,14 +463,41 @@ void SolidStrokeContents::SetStrokeCap(Cap cap) {
458
463
switch (cap) {
459
464
case Cap::kButt :
460
465
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) {};
462
468
break ;
463
469
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
+ };
465
496
break ;
466
497
case Cap::kSquare :
467
498
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) {
469
501
SolidStrokeVertexShader::PerVertexData vtx;
470
502
vtx.vertex_position = position;
471
503
vtx.pen_down = 1.0 ;
@@ -517,22 +549,25 @@ void SolidStrokeContents::SetStrokeJoin(Join join) {
517
549
case Join::kBevel :
518
550
join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
519
551
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);
522
556
};
523
557
break ;
524
558
case Join::kMiter :
525
559
join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
526
560
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) {
528
563
// 1 for no joint (straight line), 0 for max joint (180 degrees).
529
564
Scalar alignment = (start_normal.Dot (end_normal) + 1 ) / 2 ;
530
565
if (ScalarNearlyEqual (alignment, 1 )) {
531
566
return ;
532
567
}
533
568
534
- Scalar dir =
535
- CreateBevelAndGetDirection (vtx_builder, position, start_normal, end_normal);
569
+ Scalar dir = CreateBevelAndGetDirection (vtx_builder, position,
570
+ start_normal, end_normal);
536
571
537
572
Point miter_point = (start_normal + end_normal) / 2 / alignment;
538
573
if (miter_point.GetDistanceSquared ({0 , 0 }) >
@@ -549,7 +584,42 @@ void SolidStrokeContents::SetStrokeJoin(Join join) {
549
584
};
550
585
break ;
551
586
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
+ };
553
623
break ;
554
624
}
555
625
}
0 commit comments