|
10 | 10 | #include "impeller/geometry/path_builder.h"
|
11 | 11 | #include "impeller/playground/playground.h"
|
12 | 12 | #include "impeller/playground/widgets.h"
|
| 13 | +#include "impeller/renderer/render_pass.h" |
| 14 | +#include "impeller/renderer/vertex_buffer_builder.h" |
13 | 15 | #include "third_party/imgui/imgui.h"
|
14 | 16 |
|
15 | 17 | namespace impeller {
|
@@ -42,7 +44,7 @@ TEST_F(EntityTest, ThreeStrokesInOnePath) {
|
42 | 44 | Entity entity;
|
43 | 45 | entity.SetPath(path);
|
44 | 46 | auto contents = std::make_unique<SolidStrokeContents>();
|
45 |
| - contents->SetColor(Color::Red()); |
| 47 | + contents->SetColor(Color::Red().Premultiply()); |
46 | 48 | contents->SetStrokeSize(5.0);
|
47 | 49 | entity.SetContents(std::move(contents));
|
48 | 50 | ASSERT_TRUE(OpenPlaygroundHere(entity));
|
@@ -72,7 +74,7 @@ TEST_F(EntityTest, TriangleInsideASquare) {
|
72 | 74 | Entity entity;
|
73 | 75 | entity.SetPath(path);
|
74 | 76 | auto contents = std::make_unique<SolidStrokeContents>();
|
75 |
| - contents->SetColor(Color::Red()); |
| 77 | + contents->SetColor(Color::Red().Premultiply()); |
76 | 78 | contents->SetStrokeSize(20.0);
|
77 | 79 | entity.SetContents(std::move(contents));
|
78 | 80 |
|
@@ -110,7 +112,7 @@ TEST_F(EntityTest, StrokeCapAndJoinTest) {
|
110 | 112 | auto create_contents = [width = width](SolidStrokeContents::Cap cap,
|
111 | 113 | SolidStrokeContents::Join join) {
|
112 | 114 | auto contents = std::make_unique<SolidStrokeContents>();
|
113 |
| - contents->SetColor(Color::Red()); |
| 115 | + contents->SetColor(Color::Red().Premultiply()); |
114 | 116 | contents->SetStrokeSize(width);
|
115 | 117 | contents->SetStrokeCap(cap);
|
116 | 118 | contents->SetStrokeJoin(join);
|
@@ -491,5 +493,113 @@ TEST_F(EntityTest, SolidStrokeContentsSetMiter) {
|
491 | 493 | ASSERT_FLOAT_EQ(contents.GetStrokeMiter(), 8);
|
492 | 494 | }
|
493 | 495 |
|
| 496 | +TEST_F(EntityTest, BlendingModeOptions) { |
| 497 | + std::vector<const char*> blend_mode_names; |
| 498 | + std::vector<Entity::BlendMode> blend_mode_values; |
| 499 | + { |
| 500 | + // Force an exhausiveness check with a switch. When adding blend modes, |
| 501 | + // update this switch with a new name/value to to make it selectable in the |
| 502 | + // test GUI. |
| 503 | + |
| 504 | + const Entity::BlendMode b{}; |
| 505 | + static_assert( |
| 506 | + b == Entity::BlendMode::kClear); // Ensure the first item in |
| 507 | + // the switch is the first |
| 508 | + // item in the enum. |
| 509 | + switch (b) { |
| 510 | + case Entity::BlendMode::kClear: |
| 511 | + blend_mode_names.push_back("Clear"); |
| 512 | + blend_mode_values.push_back(Entity::BlendMode::kClear); |
| 513 | + case Entity::BlendMode::kSource: |
| 514 | + blend_mode_names.push_back("Source"); |
| 515 | + blend_mode_values.push_back(Entity::BlendMode::kSource); |
| 516 | + case Entity::BlendMode::kDestination: |
| 517 | + blend_mode_names.push_back("Destination"); |
| 518 | + blend_mode_values.push_back(Entity::BlendMode::kDestination); |
| 519 | + case Entity::BlendMode::kSourceOver: |
| 520 | + blend_mode_names.push_back("SourceOver"); |
| 521 | + blend_mode_values.push_back(Entity::BlendMode::kSourceOver); |
| 522 | + case Entity::BlendMode::kDestinationOver: |
| 523 | + blend_mode_names.push_back("DestinationOver"); |
| 524 | + blend_mode_values.push_back( |
| 525 | + Entity::BlendMode::kDestinationOver); |
| 526 | + }; |
| 527 | + } |
| 528 | + |
| 529 | + bool first_frame = true; |
| 530 | + auto callback = [&](ContentContext& context, RenderPass& pass) { |
| 531 | + if (first_frame) { |
| 532 | + first_frame = false; |
| 533 | + ImGui::SetNextWindowSize({350, 200}); |
| 534 | + ImGui::SetNextWindowPos({200, 450}); |
| 535 | + } |
| 536 | + |
| 537 | + auto draw_rect = [&context, &pass]( |
| 538 | + Rect rect, Color color, |
| 539 | + Entity::BlendMode blend_mode) -> bool { |
| 540 | + using VS = SolidFillPipeline::VertexShader; |
| 541 | + VertexBufferBuilder<VS::PerVertexData> vtx_builder; |
| 542 | + { |
| 543 | + auto r = rect.GetLTRB(); |
| 544 | + vtx_builder.AddVertices({ |
| 545 | + {Point(r[0], r[1])}, |
| 546 | + {Point(r[2], r[1])}, |
| 547 | + {Point(r[2], r[3])}, |
| 548 | + {Point(r[0], r[1])}, |
| 549 | + {Point(r[2], r[3])}, |
| 550 | + {Point(r[0], r[3])}, |
| 551 | + }); |
| 552 | + } |
| 553 | + |
| 554 | + Command cmd; |
| 555 | + cmd.label = "Blended Rectangle"; |
| 556 | + auto options = OptionsFromPass(pass); |
| 557 | + options.blend_mode = blend_mode; |
| 558 | + cmd.pipeline = context.GetSolidFillPipeline(options); |
| 559 | + cmd.BindVertices( |
| 560 | + vtx_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); |
| 561 | + |
| 562 | + VS::FrameInfo frame_info; |
| 563 | + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()); |
| 564 | + frame_info.color = color.Premultiply(); |
| 565 | + VS::BindFrameInfo(cmd, |
| 566 | + pass.GetTransientsBuffer().EmplaceUniform(frame_info)); |
| 567 | + |
| 568 | + cmd.primitive_type = PrimitiveType::kTriangle; |
| 569 | + |
| 570 | + return pass.AddCommand(std::move(cmd)); |
| 571 | + }; |
| 572 | + |
| 573 | + ImGui::Begin("Controls"); |
| 574 | + static Color color1(1, 0, 0, 0.5), color2(0, 1, 0, 0.5); |
| 575 | + ImGui::ColorEdit4("Color 1", reinterpret_cast<float*>(&color1)); |
| 576 | + ImGui::ColorEdit4("Color 2", reinterpret_cast<float*>(&color2)); |
| 577 | + static int current_blend_index = 3; |
| 578 | + ImGui::ListBox("Blending mode", ¤t_blend_index, |
| 579 | + blend_mode_names.data(), blend_mode_names.size()); |
| 580 | + ImGui::End(); |
| 581 | + |
| 582 | + Entity::BlendMode selected_mode = |
| 583 | + blend_mode_values[current_blend_index]; |
| 584 | + |
| 585 | + Point a, b, c, d; |
| 586 | + std::tie(a, b) = IMPELLER_PLAYGROUND_LINE( |
| 587 | + Point(400, 100), Point(200, 300), 20, Color::White(), Color::White()); |
| 588 | + std::tie(c, d) = IMPELLER_PLAYGROUND_LINE( |
| 589 | + Point(470, 190), Point(270, 390), 20, Color::White(), Color::White()); |
| 590 | + |
| 591 | + bool result = true; |
| 592 | + result = result && draw_rect(Rect(0, 0, pass.GetRenderTargetSize().width, |
| 593 | + pass.GetRenderTargetSize().height), |
| 594 | + Color(), Entity::BlendMode::kClear); |
| 595 | + result = result && draw_rect(Rect::MakeLTRB(a.x, a.y, b.x, b.y), color1, |
| 596 | + Entity::BlendMode::kSourceOver); |
| 597 | + result = result && draw_rect(Rect::MakeLTRB(c.x, c.y, d.x, d.y), color2, |
| 598 | + selected_mode); |
| 599 | + return result; |
| 600 | + }; |
| 601 | + ASSERT_TRUE(OpenPlaygroundHere(callback)); |
| 602 | +} |
| 603 | + |
494 | 604 | } // namespace testing
|
495 | 605 | } // namespace impeller
|
0 commit comments