| /* | |
| * Copyright 2025 Rive | |
| */ | |
| #include "gm.hpp" | |
| #include "gmutils.hpp" | |
| #include "rive/renderer.hpp" | |
| using namespace rivegm; | |
| using namespace rive; | |
| // Check that clockwise paths render & blend correctly with winding numbers much | |
| // larger than 1. | |
| // It's especially important to check that clockwise render modes with | |
| // transparency don't corrupt the paint after coverage is fully saturated. | |
| static void render_overdraw_paths(RenderPaintStyle style, | |
| ColorInt color0, | |
| BlendMode mode0, | |
| ColorInt color1, | |
| BlendMode mode1, | |
| ColorInt color2, | |
| BlendMode mode2, | |
| Renderer* renderer) | |
| { | |
| { | |
| // Create a region of solid dstColor to make sure we also catch the | |
| // blend modes on a==1. | |
| Paint solidWhite; | |
| solidWhite->color(0xffffffff); | |
| Path path; | |
| path->fillRule(FillRule::evenOdd); | |
| path->moveTo(10, 70); | |
| path->lineTo(130, 70); | |
| path->lineTo(130, 190); | |
| path->lineTo(10, 190); | |
| renderer->drawPath(path.get(), solidWhite.get()); | |
| } | |
| PathBuilder pathBuilder; | |
| pathBuilder.fillRule(FillRule::clockwise); | |
| for (float r : {10, 50, 40, 80, 90, 70, 60, 20, 50, 30}) | |
| { | |
| pathBuilder.addCircle(100, 100, r); | |
| } | |
| auto path = pathBuilder.detach(); | |
| Paint paint; | |
| paint->style(style); | |
| paint->thickness(20); | |
| paint->color(color0); | |
| paint->blendMode(mode0); | |
| renderer->translate(-30, -30); | |
| renderer->drawPath(path.get(), paint.get()); | |
| paint->color(color1); | |
| paint->blendMode(mode1); | |
| renderer->translate(60, 0); | |
| renderer->drawPath(path.get(), paint.get()); | |
| paint->color(color2); | |
| paint->blendMode(mode2); | |
| renderer->translate(0, 60); | |
| renderer->drawPath(path.get(), paint.get()); | |
| } | |
| DEF_SIMPLE_GM(overfill_opaque, 200, 200, renderer) | |
| { | |
| render_overdraw_paths(RenderPaintStyle::fill, | |
| 0xff00ff00, | |
| BlendMode::srcOver, | |
| 0xff0000ff, | |
| BlendMode::srcOver, | |
| 0xffff0000, | |
| BlendMode::srcOver, | |
| renderer); | |
| } | |
| DEF_SIMPLE_GM(overfill_transparent, 200, 200, renderer) | |
| { | |
| render_overdraw_paths(RenderPaintStyle::fill, | |
| 0x6000ff00, | |
| BlendMode::srcOver, | |
| 0x600000ff, | |
| BlendMode::srcOver, | |
| 0x60ff0000, | |
| BlendMode::srcOver, | |
| renderer); | |
| } | |
| DEF_SIMPLE_GM_WITH_CLEAR_COLOR(overfill_blendmodes, | |
| 0x20202020, | |
| 200, | |
| 200, | |
| renderer) | |
| { | |
| render_overdraw_paths(RenderPaintStyle::fill, | |
| // Make one opaque so we catch early out | |
| // optimizations. | |
| 0xff10f040, | |
| BlendMode::exclusion, | |
| 0x70ee905a, | |
| BlendMode::saturation, | |
| 0xb0905aee, | |
| BlendMode::luminosity, | |
| renderer); | |
| } | |
| DEF_SIMPLE_GM(overstroke_opaque, 200, 200, renderer) | |
| { | |
| render_overdraw_paths(RenderPaintStyle::stroke, | |
| 0xff00ff00, | |
| BlendMode::srcOver, | |
| 0xff0000ff, | |
| BlendMode::srcOver, | |
| 0xffff0000, | |
| BlendMode::srcOver, | |
| renderer); | |
| } | |
| DEF_SIMPLE_GM(overstroke_transparent, 200, 200, renderer) | |
| { | |
| render_overdraw_paths(RenderPaintStyle::stroke, | |
| 0x6000ff00, | |
| BlendMode::srcOver, | |
| 0x600000ff, | |
| BlendMode::srcOver, | |
| 0x60ff0000, | |
| BlendMode::srcOver, | |
| renderer); | |
| } | |
| DEF_SIMPLE_GM_WITH_CLEAR_COLOR(overstroke_blendmodes, | |
| 0x20202020, | |
| 200, | |
| 200, | |
| renderer) | |
| { | |
| render_overdraw_paths(RenderPaintStyle::stroke, | |
| // Make one opaque so we catch early out | |
| // optimizations. | |
| 0xff10f040, | |
| BlendMode::exclusion, | |
| 0x70ee905a, | |
| BlendMode::saturation, | |
| 0xb0905aee, | |
| BlendMode::luminosity, | |
| renderer); | |
| } |