12 #include "flutter/display_list/testing/dl_test_snippets.h"
13 #include "fml/logging.h"
14 #include "gtest/gtest.h"
52 #include "impeller/renderer/testing/mocks.h"
56 #include "third_party/imgui/imgui.h"
57 #include "third_party/skia/include/core/SkTextBlob.h"
74 auto image = CreateTextureForFixture(
"boston.jpg");
80 auto actual = filter->GetCoverage({});
83 ASSERT_TRUE(actual.has_value());
90 filter->SetCoverageHint(expected);
91 auto actual = filter->GetCoverage({});
93 ASSERT_TRUE(actual.has_value());
118 auto contents = std::make_unique<SolidColorContents>();
121 contents->SetGeometry(geom.get());
124 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
128 auto bridge = CreateTextureForFixture(
"bay_bridge.jpg");
140 auto contents = std::make_unique<TiledTextureContents>();
142 contents->SetGeometry(geom.get());
143 contents->SetTexture(bridge);
146 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
182 auto contents = std::make_unique<SolidColorContents>();
183 static std::unique_ptr<Geometry> geom =
185 contents->SetGeometry(geom.get());
189 return entity.
Render(context, pass);
191 ASSERT_TRUE(OpenPlaygroundHere(callback));
196 const Point margin(140, 180);
202 static Scalar miter_limit = 1.41421357;
205 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
207 ImGui::SliderFloat(
"Miter limit", &miter_limit, 0, 30);
208 ImGui::SliderFloat(
"Stroke width", &width, 0, 100);
209 if (ImGui::Button(
"Reset")) {
210 miter_limit = 1.41421357;
217 auto render_path = [width = width, &context, &pass, &world_matrix](
219 auto contents = std::make_unique<SolidColorContents>();
220 static std::unique_ptr<Geometry> geom =
222 contents->SetGeometry(geom.get());
230 if (coverage.has_value()) {
231 auto bounds_contents = std::make_unique<SolidColorContents>();
236 bounds_contents->SetGeometry(geom.get());
237 bounds_contents->SetColor(
Color::Green().WithAlpha(0.5));
239 bounds_entity.
SetContents(std::move(bounds_contents));
240 bounds_entity.
Render(context, pass);
243 entity.
Render(context, pass);
246 const Point a_def(0, 0), b_def(0, 100), c_def(150, 0), d_def(150, -100),
335 ASSERT_TRUE(OpenPlaygroundHere(callback));
342 .
MoveTo({237.164, 125.003})
343 .CubicCurveTo({236.709, 125.184}, {236.262, 125.358},
345 .CubicCurveTo({235.413, 125.68}, {234.994, 125.832},
347 .CubicCurveTo({234.592, 125.977}, {234.591, 125.977},
349 .CubicCurveTo({222.206, 130.435}, {207.708, 135.753},
351 .CubicCurveTo({162.77, 151.336}, {122.17, 156.894}, {84.1123, 160})
359 auto contents = std::make_shared<SolidColorContents>();
361 contents->SetGeometry(geom.get());
364 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
369 const char* input_axis[] = {
"X",
"Y",
"Z"};
370 static int rotation_axis_index = 0;
371 static float rotation = 0;
372 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
373 ImGui::SliderFloat(
"Rotation", &rotation, -
kPi,
kPi);
374 ImGui::Combo(
"Rotation Axis", &rotation_axis_index, input_axis,
375 sizeof(input_axis) /
sizeof(
char*));
377 switch (rotation_axis_index) {
388 rotation_matrix =
Matrix{};
392 if (ImGui::Button(
"Reset")) {
396 Matrix current_transform =
400 pass.GetRenderTargetSize().height / 2.0)));
401 Matrix result_transform = current_transform * rotation_matrix;
410 auto contents = std::make_shared<SolidColorContents>();
412 contents->SetGeometry(geom.get());
415 return entity.
Render(context, pass);
417 ASSERT_TRUE(OpenPlaygroundHere(callback));
424 .
MoveTo({359.934, 96.6335})
425 .CubicCurveTo({358.189, 96.7055}, {356.436, 96.7908},
427 .CubicCurveTo({354.571, 96.8953}, {354.469, 96.9016},
429 .CubicCurveTo({352.672, 97.0038}, {350.969, 97.113},
431 .CubicCurveTo({349.048, 97.2506}, {348.836, 97.2678},
433 .CubicCurveTo({347.019, 97.4014}, {345.407, 97.5299},
435 .CubicCurveTo({343.428, 97.704}, {343.065, 97.7402},
437 .CubicCurveTo({341.221, 97.9086}, {339.736, 98.0505},
439 .CubicCurveTo({337.702, 98.2642}, {337.156, 98.3292},
441 .CubicCurveTo({335.284, 98.5356}, {333.956, 98.6837},
443 .CubicCurveTo({332.495, 98.8635}, {332.366, 98.8818},
445 .
LineTo({332.237, 102.601})
446 .
LineTo({321.778, 102.601})
447 .
LineTo({321.778, 100.382})
448 .CubicCurveTo({321.572, 100.413}, {321.367, 100.442},
450 .CubicCurveTo({319.22, 100.79}, {317.277, 101.123},
452 .CubicCurveTo({315.322, 101.481}, {315.311, 101.482},
454 .
LineTo({310.017, 105.94})
455 .
LineTo({309.779, 105.427})
456 .
LineTo({314.403, 101.651})
457 .CubicCurveTo({314.391, 101.653}, {314.379, 101.656},
459 .CubicCurveTo({312.528, 102.001}, {310.687, 102.366},
461 .CubicCurveTo({307.85, 102.955}, {306.855, 103.182}, {305.859, 103.4})
462 .CubicCurveTo({305.048, 103.579}, {304.236, 103.75},
464 .
LineTo({299.105, 107.578})
465 .
LineTo({298.867, 107.065})
466 .
LineTo({302.394, 104.185})
467 .
LineTo({302.412, 104.171})
468 .CubicCurveTo({301.388, 104.409}, {300.366, 104.67},
470 .CubicCurveTo({298.618, 105.1}, {297.89, 105.269}, {297.165, 105.455})
471 .CubicCurveTo({295.262, 105.94}, {293.36, 106.445},
473 .CubicCurveTo({291.132, 107.072}, {290.802, 107.163},
475 .CubicCurveTo({289.463, 107.544}, {288.455, 107.839},
477 .CubicCurveTo({286.476, 108.431}, {285.506, 108.73},
479 .CubicCurveTo({283.674, 109.304}, {282.812, 109.579},
481 .CubicCurveTo({281.177, 110.112}, {280.406, 110.377},
483 .CubicCurveTo({278.458, 111.037}, {277.256, 111.449},
485 .CubicCurveTo({276.76, 111.622}, {276.716, 111.637},
487 .CubicCurveTo({275.017, 112.239}, {273.365, 112.836},
489 .
LineTo({271.717, 113.449})
490 .CubicCurveTo({271.496, 113.496}, {271.238, 113.559},
492 .CubicCurveTo({270.893, 113.645}, {270.822, 113.663},
494 .CubicCurveTo({270.468, 113.755}, {270.169, 113.834},
496 .CubicCurveTo({269.789, 113.94}, {269.732, 113.957},
498 .CubicCurveTo({269.391, 114.053}, {269.081, 114.143},
500 .CubicCurveTo({268.628, 114.276}, {268.5, 114.314},
502 .CubicCurveTo({268.172, 114.412}, {267.959, 114.478},
504 .CubicCurveTo({263.349, 115.964}, {258.058, 117.695},
506 .CubicCurveTo({253.556, 119.255}, {253.547, 119.258},
508 .CubicCurveTo({251.844, 119.849}, {250.056, 120.474},
510 .CubicCurveTo({248, 121.197}, {247.812, 121.264}, {247.621, 121.331})
511 .CubicCurveTo({247.079, 121.522}, {246.531, 121.715},
513 .CubicCurveTo({245.554, 122.06}, {245.126, 122.212},
515 .CubicCurveTo({244.071, 122.586}, {243.437, 122.811},
517 .CubicCurveTo({242.189, 123.255}, {241.58, 123.472},
519 .CubicCurveTo({240.659, 123.801}, {240.357, 123.909},
521 .CubicCurveTo({239.12, 124.351}, {238.18, 124.687}, {237.22, 125.032})
522 .
LineTo({237.164, 125.003})
523 .CubicCurveTo({236.709, 125.184}, {236.262, 125.358},
525 .CubicCurveTo({235.413, 125.68}, {234.994, 125.832},
527 .CubicCurveTo({234.592, 125.977}, {234.591, 125.977},
529 .CubicCurveTo({222.206, 130.435}, {207.708, 135.753},
531 .CubicCurveTo({162.77, 151.336}, {122.17, 156.894}, {84.1123, 160})
536 .CubicCurveTo({359.978, 96.6317}, {359.956, 96.6326},
539 .MoveTo({337.336, 124.143})
540 .CubicCurveTo({337.274, 122.359}, {338.903, 121.511},
542 .CubicCurveTo({338.903, 121.511}, {338.96, 123.303},
545 .MoveTo({340.082, 121.849})
546 .CubicCurveTo({340.074, 121.917}, {340.062, 121.992},
548 .CubicCurveTo({340.039, 122.109}, {340.031, 122.142},
550 .CubicCurveTo({340.005, 122.26}, {339.98, 122.346},
552 .CubicCurveTo({339.941, 122.473}, {339.931, 122.507},
554 .CubicCurveTo({339.873, 122.672}, {339.819, 122.804},
556 .CubicCurveTo({339.747, 122.944}, {339.743, 122.949},
558 .CubicCurveTo({339.674, 123.08}, {339.593, 123.205},
560 .CubicCurveTo({339.473, 123.366}, {339.441, 123.401},
562 .CubicCurveTo({339.332, 123.534}, {339.243, 123.625},
564 .CubicCurveTo({339.105, 123.75}, {339.068, 123.786},
566 .CubicCurveTo({338.881, 123.937}, {338.724, 124.048},
568 .CubicCurveTo({338.532, 123.959}, {338.554, 123.79},
570 .CubicCurveTo({338.58, 123.625}, {338.58, 123.625}, {338.58, 123.625})
571 .CubicCurveTo({338.607, 123.455}, {338.65, 123.299},
573 .CubicCurveTo({338.708, 123.14}, {338.71, 123.127},
575 .CubicCurveTo({338.769, 122.971}, {338.833, 122.838},
577 .CubicCurveTo({338.911, 122.702}, {338.916, 122.69200000000001},
579 .CubicCurveTo({338.996, 122.557}, {339.072, 122.444},
581 .CubicCurveTo({339.161, 122.333}, {339.166, 122.326},
583 .CubicCurveTo({339.256, 122.215}, {339.339, 122.12},
585 .CubicCurveTo({339.428, 122.033}, {339.431, 122.03},
587 .CubicCurveTo({339.785, 121.687}, {340.106, 121.511},
589 .CubicCurveTo({340.106, 121.511}, {340.107, 121.645},
592 .MoveTo({340.678, 113.245})
593 .CubicCurveTo({340.594, 113.488}, {340.356, 113.655},
595 .CubicCurveTo({339.817, 113.948}, {339.465, 114.059},
597 .CubicCurveTo({338.251, 114.379}, {337.34, 114.516},
599 .CubicCurveTo({335.761, 114.516}, {335.072, 114.527},
601 .CubicCurveTo({334.125, 114.508}, {333.862, 114.462},
603 .CubicCurveTo({332.865, 114.318}, {332.096, 114.184},
605 .CubicCurveTo({330.979, 113.695}, {330.442, 113.34},
607 .CubicCurveTo({331.135, 111.755}, {333.219, 112.946},
609 .CubicCurveTo({334.54, 113.816}, {334.554, 113.8}, {334.569, 113.784})
610 .CubicCurveTo({333.38, 112.708}, {331.749, 110.985},
612 .CubicCurveTo({333.769, 109.82}, {334.713, 111.93},
614 .CubicCurveTo({334.915, 111.889}, {334.59, 109.636},
616 .CubicCurveTo({336.733, 109.636}, {336.408, 111.889},
618 .CubicCurveTo({336.609, 111.93}, {337.553, 109.82},
620 .CubicCurveTo({339.574, 110.984}, {337.942, 112.708},
622 .CubicCurveTo({336.768, 113.8}, {336.782, 113.816},
624 .CubicCurveTo({338.104, 112.946}, {340.187, 111.755},
626 .CubicCurveTo({340.71, 112.95}, {340.728, 113.102},
629 .MoveTo({346.357, 106.771})
630 .CubicCurveTo({346.295, 104.987}, {347.924, 104.139},
632 .CubicCurveTo({347.924, 104.139}, {347.982, 105.931},
635 .MoveTo({347.56, 106.771})
636 .CubicCurveTo({347.498, 104.987}, {349.127, 104.139},
638 .CubicCurveTo({349.127, 104.139}, {349.185, 105.931},
647 auto contents = std::make_shared<SolidColorContents>();
649 contents->SetGeometry(geom.get());
652 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
660 ASSERT_EQ(path_geometry->GetStrokeCap(),
Cap::kButt);
661 ASSERT_EQ(path_geometry->GetStrokeJoin(),
Join::kMiter);
673 ASSERT_EQ(path_geometry->GetStrokeCap(),
Cap::kRound);
681 ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 4);
688 ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 8);
695 ASSERT_FLOAT_EQ(path_geometry->GetMiterLimit(), 4);
700 std::vector<const char*> blend_mode_names;
701 std::vector<BlendMode> blend_mode_values;
714 blend_mode_names.push_back(
"Clear");
717 blend_mode_names.push_back(
"Source");
720 blend_mode_names.push_back(
"Destination");
723 blend_mode_names.push_back(
"SourceOver");
726 blend_mode_names.push_back(
"DestinationOver");
729 blend_mode_names.push_back(
"SourceIn");
732 blend_mode_names.push_back(
"DestinationIn");
735 blend_mode_names.push_back(
"SourceOut");
738 blend_mode_names.push_back(
"DestinationOut");
741 blend_mode_names.push_back(
"SourceATop");
744 blend_mode_names.push_back(
"DestinationATop");
747 blend_mode_names.push_back(
"Xor");
750 blend_mode_names.push_back(
"Plus");
753 blend_mode_names.push_back(
"Modulate");
760 auto draw_rect = [&context, &pass, &world_matrix](
767 auto r = rect.GetLTRB();
778 pass.SetCommandLabel(
"Blended Rectangle");
780 options.blend_mode = blend_mode;
783 pass.SetVertexBuffer(
786 VS::FrameInfo frame_info;
787 frame_info.mvp = pass.GetOrthographicTransform() * world_matrix;
790 FS::FragInfo frag_info;
791 frag_info.color =
color.Premultiply();
794 return pass.Draw().ok();
797 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
798 static Color color1(1, 0, 0, 0.5), color2(0, 1, 0, 0.5);
799 ImGui::ColorEdit4(
"Color 1",
reinterpret_cast<float*
>(&color1));
800 ImGui::ColorEdit4(
"Color 2",
reinterpret_cast<float*
>(&color2));
801 static int current_blend_index = 3;
802 ImGui::ListBox(
"Blending mode", ¤t_blend_index,
803 blend_mode_names.data(), blend_mode_names.size());
806 BlendMode selected_mode = blend_mode_values[current_blend_index];
819 pass.GetRenderTargetSize().height),
827 ASSERT_TRUE(OpenPlaygroundHere(callback));
832 static float scale = 20;
834 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
835 ImGui::SliderFloat(
"Scale", &
scale, 1, 100);
842 .CubicCurveTo({98.50862885295136, 34.81812293973836},
843 {99.46822048142015, 33.85863261475589},
844 {99.46822048142015, 32.67499810206613})
845 .CubicCurveTo({99.46822048142015, 31.491363589376355},
846 {98.50862885295136, 30.53187326439389},
847 {97.32499434685802, 30.531998226542708})
848 .CubicCurveTo({96.14153655073771, 30.532123170035373},
849 {95.18222070648729, 31.491540299350355},
850 {95.18222070648729, 32.67499810206613})
851 .CubicCurveTo({95.18222070648729, 33.85845590478189},
852 {96.14153655073771, 34.81787303409686},
853 {97.32499434685802, 34.81799797758954})
861 auto contents = std::make_shared<SolidColorContents>();
863 contents->SetGeometry(geom.get());
866 return entity.
Render(context, pass);
868 ASSERT_TRUE(OpenPlaygroundHere(callback));
872 auto bridge = CreateTextureForFixture(
"bay_bridge.jpg");
873 auto boston = CreateTextureForFixture(
"boston.jpg");
874 auto kalimba = CreateTextureForFixture(
"kalimba.jpg");
875 ASSERT_TRUE(bridge && boston && kalimba);
893 entity.SetContents(blend1);
894 return entity.Render(context, pass);
896 ASSERT_TRUE(OpenPlaygroundHere(callback));
901 CreateTextureForFixture(
"boston.jpg",
true);
905 const char* input_type_names[] = {
"Texture",
"Solid Color"};
906 const char* blur_type_names[] = {
"Image blur",
"Mask blur"};
907 const char* pass_variation_names[] = {
"New"};
908 const char* blur_style_names[] = {
"Normal",
"Solid",
"Outer",
"Inner"};
909 const char* tile_mode_names[] = {
"Clamp",
"Repeat",
"Mirror",
"Decal"};
918 static int selected_input_type = 0;
920 static int selected_blur_type = 0;
921 static int selected_pass_variation = 0;
922 static bool combined_sigma =
false;
923 static float blur_amount_coarse[2] = {0, 0};
924 static float blur_amount_fine[2] = {10, 10};
925 static int selected_blur_style = 0;
926 static int selected_tile_mode = 3;
927 static Color cover_color(1, 0, 0, 0.2);
928 static Color bounds_color(0, 1, 0, 0.1);
929 static float offset[2] = {500, 400};
930 static float rotation = 0;
931 static float scale[2] = {0.65, 0.65};
932 static float skew[2] = {0, 0};
933 static float path_rect[4] = {0, 0,
934 static_cast<float>(boston->GetSize().width),
935 static_cast<float>(boston->GetSize().height)};
937 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
939 ImGui::Combo(
"Input type", &selected_input_type, input_type_names,
940 sizeof(input_type_names) /
sizeof(
char*));
941 if (selected_input_type == 0) {
942 ImGui::SliderFloat(
"Input opacity", &input_color.
alpha, 0, 1);
944 ImGui::ColorEdit4(
"Input color",
945 reinterpret_cast<float*
>(&input_color));
947 ImGui::Combo(
"Blur type", &selected_blur_type, blur_type_names,
948 sizeof(blur_type_names) /
sizeof(
char*));
949 if (selected_blur_type == 0) {
950 ImGui::Combo(
"Pass variation", &selected_pass_variation,
951 pass_variation_names,
952 sizeof(pass_variation_names) /
sizeof(
char*));
954 ImGui::Checkbox(
"Combined sigma", &combined_sigma);
955 if (combined_sigma) {
956 ImGui::SliderFloat(
"Sigma (coarse)", blur_amount_coarse, 0, 1000);
957 ImGui::SliderFloat(
"Sigma (fine)", blur_amount_fine, 0, 10);
958 blur_amount_coarse[1] = blur_amount_coarse[0];
959 blur_amount_fine[1] = blur_amount_fine[0];
961 ImGui::SliderFloat2(
"Sigma (coarse)", blur_amount_coarse, 0, 1000);
962 ImGui::SliderFloat2(
"Sigma (fine)", blur_amount_fine, 0, 10);
964 ImGui::Combo(
"Blur style", &selected_blur_style, blur_style_names,
965 sizeof(blur_style_names) /
sizeof(
char*));
966 ImGui::Combo(
"Tile mode", &selected_tile_mode, tile_mode_names,
967 sizeof(tile_mode_names) /
sizeof(
char*));
968 ImGui::ColorEdit4(
"Cover color",
reinterpret_cast<float*
>(&cover_color));
969 ImGui::ColorEdit4(
"Bounds color ",
970 reinterpret_cast<float*
>(&bounds_color));
971 ImGui::SliderFloat2(
"Translation",
offset, 0,
972 pass.GetRenderTargetSize().width);
973 ImGui::SliderFloat(
"Rotation", &rotation, 0,
kPi * 2);
974 ImGui::SliderFloat2(
"Scale",
scale, 0, 3);
975 ImGui::SliderFloat2(
"Skew", skew, -3, 3);
976 ImGui::SliderFloat4(
"Path XYWH", path_rect, -1000, 1000);
980 auto blur_sigma_x =
Sigma{blur_amount_coarse[0] + blur_amount_fine[0]};
981 auto blur_sigma_y =
Sigma{blur_amount_coarse[1] + blur_amount_fine[1]};
983 std::shared_ptr<Contents> input;
987 Rect::MakeXYWH(path_rect[0], path_rect[1], path_rect[2], path_rect[3]);
988 if (selected_input_type == 0) {
989 auto texture = std::make_shared<TextureContents>();
991 texture->SetDestinationRect(input_rect);
992 texture->SetTexture(boston);
993 texture->SetOpacity(input_color.
alpha);
996 input_size = input_rect.GetSize();
998 auto fill = std::make_shared<SolidColorContents>();
999 fill->SetColor(input_color);
1000 static std::unique_ptr<Geometry> geom =
1003 fill->SetGeometry(geom.get());
1006 input_size = input_rect.GetSize();
1009 std::shared_ptr<FilterContents> blur;
1010 switch (selected_pass_variation) {
1012 blur = std::make_shared<GaussianBlurFilterContents>(
1013 blur_sigma_x.sigma, blur_sigma_y.sigma,
1014 tile_modes[selected_tile_mode], blur_styles[selected_blur_style],
1021 tile_modes[selected_tile_mode], blur_styles[selected_blur_style]);
1028 blur_styles[selected_blur_style]);
1037 auto target_contents = selected_blur_type == 0 ? blur : mask_blur;
1043 entity.
Render(context, pass);
1048 static std::unique_ptr<Geometry> geom =
1050 auto contents = std::make_shared<SolidColorContents>();
1051 contents->SetColor(cover_color);
1052 contents->SetGeometry(geom.get());
1055 cover_entity.
Render(context, pass);
1059 std::optional<Rect> target_contents_coverage =
1061 if (target_contents_coverage.has_value()) {
1064 .
AddRect(target_contents->GetCoverage(entity).value())
1066 auto contents = std::make_shared<SolidColorContents>();
1067 contents->SetColor(bounds_color);
1068 contents->SetGeometry(geom.get());
1072 bounds_entity.
Render(context, pass);
1077 ASSERT_TRUE(OpenPlaygroundHere(callback));
1081 auto boston = CreateTextureForFixture(
"boston.jpg");
1082 ASSERT_TRUE(boston);
1085 const char* morphology_type_names[] = {
"Dilate",
"Erode"};
1090 static int selected_morphology_type = 0;
1091 static float radius[2] = {20, 20};
1092 static Color cover_color(1, 0, 0, 0.2);
1093 static Color bounds_color(0, 1, 0, 0.1);
1094 static float offset[2] = {500, 400};
1095 static float rotation = 0;
1096 static float scale[2] = {0.65, 0.65};
1097 static float skew[2] = {0, 0};
1098 static float path_rect[4] = {0, 0,
1099 static_cast<float>(boston->GetSize().width),
1100 static_cast<float>(boston->GetSize().height)};
1101 static float effect_transform_scale = 1;
1103 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1105 ImGui::Combo(
"Morphology type", &selected_morphology_type,
1106 morphology_type_names,
1107 sizeof(morphology_type_names) /
sizeof(
char*));
1108 ImGui::SliderFloat2(
"Radius", radius, 0, 200);
1109 ImGui::SliderFloat(
"Input opacity", &input_color.
alpha, 0, 1);
1110 ImGui::ColorEdit4(
"Cover color",
reinterpret_cast<float*
>(&cover_color));
1111 ImGui::ColorEdit4(
"Bounds color ",
1112 reinterpret_cast<float*
>(&bounds_color));
1113 ImGui::SliderFloat2(
"Translation",
offset, 0,
1114 pass.GetRenderTargetSize().width);
1115 ImGui::SliderFloat(
"Rotation", &rotation, 0,
kPi * 2);
1116 ImGui::SliderFloat2(
"Scale",
scale, 0, 3);
1117 ImGui::SliderFloat2(
"Skew", skew, -3, 3);
1118 ImGui::SliderFloat4(
"Path XYWH", path_rect, -1000, 1000);
1119 ImGui::SliderFloat(
"Effect transform scale", &effect_transform_scale, 0,
1124 std::shared_ptr<Contents> input;
1128 Rect::MakeXYWH(path_rect[0], path_rect[1], path_rect[2], path_rect[3]);
1129 auto texture = std::make_shared<TextureContents>();
1131 texture->SetDestinationRect(input_rect);
1132 texture->SetTexture(boston);
1133 texture->SetOpacity(input_color.
alpha);
1136 input_size = input_rect.GetSize();
1140 morphology_types[selected_morphology_type]);
1142 Vector2{effect_transform_scale, effect_transform_scale}));
1155 entity.
Render(context, pass);
1160 static std::unique_ptr<Geometry> geom =
1162 auto cover_contents = std::make_shared<SolidColorContents>();
1163 cover_contents->SetColor(cover_color);
1164 cover_contents->SetGeometry(geom.get());
1167 cover_entity.
Render(context, pass);
1173 .
AddRect(contents->GetCoverage(entity).value())
1175 auto bounds_contents = std::make_shared<SolidColorContents>();
1176 bounds_contents->SetColor(bounds_color);
1177 bounds_contents->SetGeometry(bounds_geom.get());
1178 bounds_entity.
SetContents(std::move(bounds_contents));
1181 bounds_entity.
Render(context, pass);
1185 ASSERT_TRUE(OpenPlaygroundHere(callback));
1197 entity.
SetContents(std::make_shared<SolidColorContents>());
1208 auto contents = std::make_unique<SolidColorContents>();
1209 contents->SetGeometry(geometry.get());
1215 ASSERT_TRUE(actual.has_value());
1226 auto contents = std::make_unique<SolidColorContents>();
1227 contents->SetGeometry(geometry.get());
1234 ASSERT_TRUE(actual.has_value());
1245 auto contents = std::make_unique<SolidColorContents>();
1246 contents->SetGeometry(geometry.get());
1252 ASSERT_TRUE(actual.has_value());
1258 auto fill = std::make_shared<SolidColorContents>();
1261 fill->SetGeometry(geom.get());
1269 auto actual = border_mask_blur->GetCoverage(e);
1271 ASSERT_TRUE(actual.has_value());
1278 auto actual = border_mask_blur->GetCoverage(e);
1279 auto expected =
Rect::MakeXYWH(-287.792, -4.94975, 504.874, 504.874);
1280 ASSERT_TRUE(actual.has_value());
1288 auto fill = std::make_shared<SolidColorContents>();
1293 fill->SetGeometry(geom.get());
1295 auto coverage = fill->GetCoverage({});
1296 ASSERT_TRUE(coverage.has_value());
1302 auto fill = std::make_shared<SolidColorContents>();
1306 fill->SetGeometry(geom.get());
1314 ASSERT_TRUE(coverage.has_value());
1320 auto fill = std::make_shared<SolidColorContents>();
1324 fill->SetGeometry(geom.get());
1326 auto coverage = fill->GetCoverage({});
1327 ASSERT_FALSE(coverage.has_value());
1334 auto clip = std::make_shared<ClipContents>();
1336 auto result = clip->GetClipCoverage(
Entity{},
Rect{});
1338 ASSERT_FALSE(result.coverage.has_value());
1343 auto clip = std::make_shared<ClipContents>();
1347 clip->SetGeometry(geom.get());
1348 auto result = clip->GetClipCoverage(
Entity{},
Rect{});
1350 ASSERT_FALSE(result.coverage.has_value());
1355 auto clip = std::make_shared<ClipContents>();
1360 ASSERT_FALSE(result.coverage.has_value());
1365 auto clip = std::make_shared<ClipContents>();
1369 clip->SetGeometry(geom.get());
1373 ASSERT_TRUE(result.coverage.has_value());
1380 auto clip = std::make_shared<ClipContents>();
1384 clip->SetGeometry(geom.get());
1388 ASSERT_TRUE(result.coverage.has_value());
1397 static float corner_radius = 100;
1399 static bool show_coverage =
false;
1402 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1403 ImGui::SliderFloat(
"Corner radius", &corner_radius, 0, 300);
1404 ImGui::SliderFloat(
"Blur radius", &
blur_radius, 0, 300);
1405 ImGui::ColorEdit4(
"Color",
reinterpret_cast<Scalar*
>(&
color));
1406 ImGui::Checkbox(
"Show coverage", &show_coverage);
1407 if (show_coverage) {
1408 ImGui::ColorEdit4(
"Coverage color",
1409 reinterpret_cast<Scalar*
>(&coverage_color));
1416 auto [top_left, bottom_right] =
1419 Rect::MakeLTRB(top_left.x, top_left.y, bottom_right.x, bottom_right.y);
1421 auto contents = std::make_unique<SolidRRectBlurContents>();
1422 contents->SetRRect(rect, {corner_radius, corner_radius});
1423 contents->SetColor(
color);
1429 entity.
Render(context, pass);
1432 if (show_coverage && coverage.has_value()) {
1433 auto bounds_contents = std::make_unique<SolidColorContents>();
1436 bounds_contents->SetGeometry(geom.get());
1437 bounds_contents->SetColor(coverage_color.
Premultiply());
1439 bounds_entity.
SetContents(std::move(bounds_contents));
1440 bounds_entity.
Render(context, pass);
1445 ASSERT_TRUE(OpenPlaygroundHere(callback));
1450 auto fill = std::make_shared<SolidColorContents>();
1453 fill->SetGeometry(geom.get());
1471 auto actual = filter->GetCoverage(e);
1474 ASSERT_TRUE(actual.has_value());
1479 auto bay_bridge = CreateTextureForFixture(
"bay_bridge.jpg");
1480 ASSERT_TRUE(bay_bridge);
1490 static float offset[2] = {500, 400};
1491 static float rotation = 0;
1492 static float scale[2] = {0.65, 0.65};
1493 static float skew[2] = {0, 0};
1496 ImGui::Begin(
"Color Matrix",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1498 std::string label =
"##1";
1499 for (
int i = 0; i < 20; i += 5) {
1500 ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
1501 &(color_matrix.
array[i]), 5,
nullptr,
nullptr,
1506 ImGui::SliderFloat2(
"Translation", &
offset[0], 0,
1507 pass.GetRenderTargetSize().width);
1508 ImGui::SliderFloat(
"Rotation", &rotation, 0,
kPi * 2);
1509 ImGui::SliderFloat2(
"Scale", &
scale[0], 0, 3);
1510 ImGui::SliderFloat2(
"Skew", &skew[0], -3, 3);
1528 entity.
Render(context, pass);
1533 ASSERT_TRUE(OpenPlaygroundHere(callback));
1540 auto fill = std::make_shared<SolidColorContents>();
1541 fill->SetGeometry(geom.get());
1551 auto actual = filter->GetCoverage(e);
1554 ASSERT_TRUE(actual.has_value());
1559 auto image = CreateTextureForFixture(
"kalimba.jpg");
1582 return entity_left.
Render(context, pass) &&
1583 entity_right.
Render(context, pass);
1586 ASSERT_TRUE(OpenPlaygroundHere(callback));
1591 auto fill = std::make_shared<SolidColorContents>();
1594 fill->SetGeometry(geom.get());
1604 auto actual = filter->GetCoverage(e);
1607 ASSERT_TRUE(actual.has_value());
1612 auto image = CreateTextureForFixture(
"embarcadero.jpg");
1635 return entity_left.
Render(context, pass) &&
1636 entity_right.
Render(context, pass);
1639 ASSERT_TRUE(OpenPlaygroundHere(callback));
1644 switch (yuv_color_space) {
1646 yuv.
x = rgb.
x * 0.299 + rgb.
y * 0.587 + rgb.
z * 0.114;
1647 yuv.
y = rgb.
x * -0.169 + rgb.
y * -0.331 + rgb.
z * 0.5 + 0.5;
1648 yuv.
z = rgb.
x * 0.5 + rgb.
y * -0.419 + rgb.
z * -0.081 + 0.5;
1651 yuv.
x = rgb.
x * 0.257 + rgb.
y * 0.516 + rgb.
z * 0.100 + 0.063;
1652 yuv.
y = rgb.
x * -0.145 + rgb.
y * -0.291 + rgb.
z * 0.439 + 0.5;
1653 yuv.
z = rgb.
x * 0.429 + rgb.
y * -0.368 + rgb.
z * -0.071 + 0.5;
1662 Vector3 red = {244.0 / 255.0, 67.0 / 255.0, 54.0 / 255.0};
1663 Vector3 green = {76.0 / 255.0, 175.0 / 255.0, 80.0 / 255.0};
1664 Vector3 blue = {33.0 / 255.0, 150.0 / 255.0, 243.0 / 255.0};
1665 Vector3 white = {1.0, 1.0, 1.0};
1670 std::vector<Vector3> yuvs{red_yuv, green_yuv, blue_yuv, white_yuv};
1671 std::vector<uint8_t> y_data;
1672 std::vector<uint8_t> uv_data;
1673 for (
int i = 0; i < 4; i++) {
1675 uint8_t y = std::round(yuv.x * 255.0);
1676 uint8_t u = std::round(yuv.y * 255.0);
1677 uint8_t v = std::round(yuv.z * 255.0);
1678 for (
int j = 0; j < 16; j++) {
1679 y_data.push_back(y);
1681 for (
int j = 0; j < 8; j++) {
1682 uv_data.push_back(j % 2 == 0 ? u : v);
1686 auto blit_pass = cmd_buffer->CreateBlitPass();
1691 y_texture_descriptor.
size = {8, 8};
1694 auto y_mapping = std::make_shared<fml::DataMapping>(y_data);
1695 auto y_mapping_buffer =
1703 uv_texture_descriptor.
size = {4, 4};
1706 auto uv_mapping = std::make_shared<fml::DataMapping>(uv_data);
1707 auto uv_mapping_buffer =
1714 FML_DLOG(ERROR) <<
"Could not copy contents into Y/UV texture.";
1717 return {y_texture, uv_texture};
1724 <<
"YUV to RGB filter is not supported on OpenGLES backend yet.";
1730 for (
int i = 0; i < 2; i++) {
1731 auto yuv_color_space = yuv_color_space_array[i];
1735 textures[0], textures[1], yuv_color_space);
1738 auto snapshot = filter_contents->RenderToSnapshot(context, filter_entity);
1742 contents->SetTexture(snapshot->texture);
1743 contents->SetSourceRect(
Rect::MakeSize(snapshot->texture->GetSize()));
1747 entity.
Render(context, pass);
1751 ASSERT_TRUE(OpenPlaygroundHere(callback));
1755 auto runtime_stages =
1756 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1757 auto runtime_stage =
1759 ASSERT_TRUE(runtime_stage);
1760 ASSERT_TRUE(runtime_stage->IsDirty());
1762 bool expect_dirty =
true;
1767 EXPECT_EQ(runtime_stage->IsDirty(), expect_dirty);
1769 auto contents = std::make_shared<RuntimeEffectContents>();
1770 contents->SetGeometry(geom.get());
1771 contents->SetRuntimeStage(runtime_stage);
1773 struct FragUniforms {
1777 .iResolution =
Vector2(GetWindowSize().width, GetWindowSize().height),
1778 .iTime =
static_cast<Scalar>(GetSecondsElapsed()),
1780 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
1781 uniform_data->resize(
sizeof(FragUniforms));
1782 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
1783 contents->SetUniformData(uniform_data);
1787 bool result = contents->Render(context, entity, pass);
1790 EXPECT_NE(first_pipeline, pass.GetCommands().back().pipeline.get());
1791 first_pipeline = pass.GetCommands().back().pipeline.get();
1793 EXPECT_EQ(pass.GetCommands().back().pipeline.get(), first_pipeline);
1796 expect_dirty =
false;
1801 auto content_context = GetContentContext();
1804 content_context->GetRenderTargetCache()->CreateOffscreen(
1805 *content_context->GetContext(), {1, 1}, 1u);
1807 testing::MockRenderPass mock_pass(GetContext(), target);
1808 callback(*content_context, mock_pass);
1809 callback(*content_context, mock_pass);
1812 runtime_stages = OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1816 ASSERT_TRUE(runtime_stage->IsDirty());
1817 expect_dirty =
true;
1819 callback(*content_context, mock_pass);
1824 auto runtime_stages =
1825 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1826 auto runtime_stage =
1828 ASSERT_TRUE(runtime_stage);
1829 ASSERT_TRUE(runtime_stage->IsDirty());
1831 auto contents = std::make_shared<RuntimeEffectContents>();
1833 contents->SetGeometry(geom.get());
1834 contents->SetRuntimeStage(runtime_stage);
1836 struct FragUniforms {
1840 .iResolution =
Vector2(GetWindowSize().width, GetWindowSize().height),
1841 .iTime =
static_cast<Scalar>(GetSecondsElapsed()),
1843 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
1844 uniform_data->resize(
sizeof(FragUniforms));
1845 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
1846 contents->SetUniformData(uniform_data);
1854 GetContentContext()->GetRenderTargetCache()->CreateOffscreenMSAA(
1855 *GetContext(), {GetWindowSize().width, GetWindowSize().height}, 1,
1856 "RuntimeEffect Texture");
1857 testing::MockRenderPass pass(GetContext(), target);
1859 ASSERT_TRUE(contents->Render(*GetContentContext(), entity, pass));
1860 ASSERT_EQ(pass.GetCommands().size(), 1u);
1861 const auto& command = pass.GetCommands()[0];
1862 ASSERT_TRUE(command.pipeline->GetDescriptor()
1863 .GetDepthStencilAttachmentDescriptor()
1865 ASSERT_TRUE(command.pipeline->GetDescriptor()
1866 .GetFrontStencilAttachmentDescriptor()
1871 auto runtime_stages =
1872 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1873 auto runtime_stage =
1875 ASSERT_TRUE(runtime_stage);
1876 ASSERT_TRUE(runtime_stage->IsDirty());
1878 auto contents = std::make_shared<RuntimeEffectContents>();
1879 contents->SetRuntimeStage(runtime_stage);
1881 EXPECT_TRUE(contents->BootstrapShader(*GetContentContext()));
1886 GTEST_SKIP() <<
"Test only applies to Vulkan";
1889 auto runtime_stages =
1890 OpenAssetAsRuntimeStage(
"runtime_stage_example.frag.iplr");
1891 auto runtime_stage =
1893 ASSERT_TRUE(runtime_stage);
1894 ASSERT_TRUE(runtime_stage->IsDirty());
1896 auto contents = std::make_shared<RuntimeEffectContents>();
1898 contents->SetGeometry(geom.get());
1899 contents->SetRuntimeStage(runtime_stage);
1901 struct FragUniforms {
1905 .iResolution =
Vector2(GetWindowSize().width, GetWindowSize().height),
1906 .iTime =
static_cast<Scalar>(GetSecondsElapsed()),
1908 auto uniform_data = std::make_shared<std::vector<uint8_t>>();
1909 uniform_data->resize(
sizeof(FragUniforms));
1910 memcpy(uniform_data->data(), &frag_uniforms,
sizeof(FragUniforms));
1911 contents->SetUniformData(uniform_data);
1916 auto context = GetContentContext();
1917 RenderTarget target = context->GetRenderTargetCache()->CreateOffscreen(
1918 *context->GetContext(), {1, 1}, 1u);
1920 testing::MockRenderPass pass(GetContext(), target);
1921 ASSERT_TRUE(contents->Render(*context, entity, pass));
1922 ASSERT_EQ(pass.GetCommands().size(), 1u);
1923 const auto& command = pass.GetCommands()[0];
1924 ASSERT_EQ(command.fragment_bindings.buffers.size(), 1u);
1929 EXPECT_EQ(command.fragment_bindings.buffers[0].view.resource.range.length,
1934 auto image = CreateTextureForFixture(
"boston.jpg");
1944 return entity.
Render(context, pass);
1946 ASSERT_TRUE(OpenPlaygroundHere(callback));
1950 auto image = CreateTextureForFixture(
"boston.jpg");
1960 return entity.
Render(context, pass);
1962 ASSERT_TRUE(OpenPlaygroundHere(callback));
1966 auto image = CreateTextureForFixture(
"boston.jpg");
1976 return entity.
Render(context, pass);
1978 ASSERT_TRUE(OpenPlaygroundHere(callback));
1982 auto image = CreateTextureForFixture(
"boston.jpg");
1992 return entity.
Render(context, pass);
1994 ASSERT_TRUE(OpenPlaygroundHere(callback));
1998 auto image = CreateTextureForFixture(
"boston.jpg");
2008 return entity.
Render(context, pass);
2010 ASSERT_TRUE(OpenPlaygroundHere(callback));
2029 auto coverage = geometry->GetCoverage(
transform);
2040 EXPECT_TRUE(contents.
IsOpaque(matrix));
2042 EXPECT_FALSE(contents.
IsOpaque(matrix));
2051 EXPECT_FALSE(contents.
IsOpaque(matrix));
2061 EXPECT_FALSE(contents.
IsOpaque(matrix));
2063 EXPECT_FALSE(contents.
IsOpaque(matrix));
2072 EXPECT_FALSE(contents.
IsOpaque(matrix));
2082 EXPECT_TRUE(contents.
IsOpaque(matrix));
2084 EXPECT_FALSE(contents.
IsOpaque(matrix));
2087 EXPECT_FALSE(contents.
IsOpaque(matrix));
2096 EXPECT_FALSE(contents.
IsOpaque(matrix));
2106 EXPECT_TRUE(contents.
IsOpaque(matrix));
2108 EXPECT_FALSE(contents.
IsOpaque(matrix));
2111 EXPECT_FALSE(contents.
IsOpaque(matrix));
2120 EXPECT_FALSE(contents.
IsOpaque(matrix));
2130 EXPECT_TRUE(contents.
IsOpaque(matrix));
2132 EXPECT_FALSE(contents.
IsOpaque(matrix));
2135 EXPECT_FALSE(contents.
IsOpaque(matrix));
2144 EXPECT_FALSE(contents.
IsOpaque(matrix));
2149 auto bay_bridge = CreateTextureForFixture(
"bay_bridge.jpg");
2155 EXPECT_FALSE(contents.
IsOpaque(matrix));
2159 std::vector<Point> points = {{10, 20}, {100, 200}};
2169 auto src_contents = std::make_shared<SolidColorContents>();
2171 src_contents->SetGeometry(src_geom.get());
2174 auto dst_contents = std::make_shared<SolidColorContents>();
2176 dst_contents->SetGeometry(dst_geom.get());
2183 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
2195 auto content_context = GetContentContext();
2197 auto default_gyph = content_context->GetGlyphAtlasPipeline({
2199 .has_depth_stencil_attachments =
false,
2201 auto alt_gyph = content_context->GetGlyphAtlasPipeline(
2203 .has_depth_stencil_attachments =
true});
2205 EXPECT_NE(default_gyph, alt_gyph);
2206 EXPECT_EQ(default_gyph->GetDescriptor().GetSpecializationConstants(),
2207 alt_gyph->GetDescriptor().GetSpecializationConstants());
2209 auto use_a8 = GetContext()->GetCapabilities()->GetDefaultGlyphAtlasFormat() ==
2212 std::vector<Scalar> expected_constants = {
static_cast<Scalar>(use_a8)};
2213 EXPECT_EQ(default_gyph->GetDescriptor().GetSpecializationConstants(),
2214 expected_constants);
2218 auto content_context = GetContentContext();
2219 auto default_color_burn = content_context->GetMorphologyFilterPipeline({
2223 auto decal_supported =
static_cast<Scalar>(
2224 GetContext()->GetCapabilities()->SupportsDecalSamplerAddressMode());
2225 std::vector<Scalar> expected_constants = {decal_supported};
2226 ASSERT_EQ(default_color_burn->GetDescriptor().GetSpecializationConstants(),
2227 expected_constants);
2246 EXPECT_NE(hash_a, hash_b);
2247 EXPECT_NE(hash_b, hash_c);
2248 EXPECT_NE(hash_c, hash_d);
2265 bool expected_layout =
false;
2267 FragmentShader::kDescriptorSetLayouts) {
2268 if (layout.binding == 64 &&
2270 expected_layout =
true;
2273 EXPECT_TRUE(expected_layout);
2279 testing::MockRenderPass mock_pass(GetContext(), target);
2281 auto get_result = [
this, &mock_pass](
const Path& path) {
2284 return geometry->GetPositionBuffer(*GetContentContext(), {}, mock_pass);
2313 GTEST_SKIP() <<
"Validation is only fatal on Vulkan backend.";
2318 GetContentContext()->GetBlendColorBurnPipeline({
2320 .has_depth_stencil_attachments =
false,
2336 GetContentContext()->GetRenderTargetCache()->CreateOffscreen(
2337 *GetContext(), {1, 1}, 1u);
2338 testing::MockRenderPass render_pass(GetContext(), target);
2339 auto position_result =
2340 geom->GetPositionBuffer(*GetContentContext(), entity, render_pass);
2342 EXPECT_EQ(position_result.vertex_buffer.vertex_count, 0u);
2354 auto contents = std::make_shared<SolidColorContents>();
2356 contents->SetGeometry(geom.get());
2363 ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
2369 static float alpha = 10;
2370 static float beta = 10;
2371 static float radius = 40;
2372 static int degree = 4;
2375 ImGui::Begin(
"Controls",
nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2376 ImGui::SliderFloat(
"Alpha", &alpha, 0, 100);
2377 ImGui::SliderFloat(
"Beta", &beta, 0, 100);
2378 ImGui::SliderInt(
"Degreee", °ree, 1, 20);
2379 ImGui::SliderFloat(
"Radius", &radius, 0, 400);
2380 ImGui::ColorEdit4(
"Color",
reinterpret_cast<float*
>(&
color));
2383 auto contents = std::make_shared<SolidColorContents>();
2384 static std::unique_ptr<SuperellipseGeometry> geom =
2385 std::make_unique<SuperellipseGeometry>(
Point{400, 400}, radius, degree,
2387 contents->SetColor(
color);
2388 contents->SetGeometry(geom.get());
2393 return entity.
Render(context, pass);
2396 ASSERT_TRUE(OpenPlaygroundHere(callback));
2402 auto result = contents.ApplyColorFilter([](
const Color&
color) {
2405 ASSERT_TRUE(result);
2407 Color(0.424452, 0.828743, 0.79105, 0.9375));
2410 #define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \
2411 TEST_P(EntityTest, name##GradientApplyColorFilter) { \
2412 auto contents = name##GradientContents(); \
2413 contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \
2414 auto result = contents.ApplyColorFilter([](const Color& color) { \
2415 return color.Blend(Color::LimeGreen().WithAlpha(0.75), \
2416 BlendMode::kScreen); \
2418 ASSERT_TRUE(result); \
2420 std::vector<Color> expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \
2421 ASSERT_COLORS_NEAR(contents.GetColors(), expected); \