| /* |
| * Copyright 2013 Google Inc. |
| * Copyright 2022 Rive |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "gm.hpp" |
| #include "gmutils.hpp" |
| #include "rive/renderer.hpp" |
| #include "rive/math/math_types.hpp" |
| #include "rive/math/vec2d.hpp" |
| #include "rive/math/mat2d.hpp" |
| #include "common/rand.hpp" |
| |
| using namespace rivegm; |
| using namespace rive; |
| |
| /** |
| * Renders overlapping shapes with colorburn against a checkerboard. |
| */ |
| class DstReadShuffle : public GM |
| { |
| public: |
| DstReadShuffle() : GM(530, 690) {} |
| |
| protected: |
| enum ShapeType |
| { |
| kCircle_ShapeType, |
| kRoundRect_ShapeType, |
| kRect_ShapeType, |
| kConvexPath_ShapeType, |
| kPolygonFan_ShapeType, |
| kConcavePath_ShapeType, |
| kNumShapeTypes |
| }; |
| |
| static void fan_polygon(PathBuilder& builder, |
| float a0, |
| float a1, |
| float x, |
| float y, |
| float rx, |
| float ry, |
| int depth) |
| { |
| if (depth <= 0) |
| { |
| return; |
| } |
| float ai = (a0 + a1) / 2; |
| builder.moveTo(cosf(a0) * rx + x, sinf(a0) * ry + y); |
| builder.lineTo(cosf(ai) * rx + x, sinf(ai) * ry + y); |
| builder.lineTo(cosf(a1) * rx + x, sinf(a1) * ry + y); |
| builder.close(); |
| fan_polygon(builder, a0, ai, x, y, rx, ry, depth - 1); |
| fan_polygon(builder, ai, a1, x, y, rx, ry, depth - 1); |
| } |
| |
| void drawShape(Renderer* renderer, const Paint& paint, ShapeType type) |
| { |
| const float l = 0, t = 0, r = 75, b = 85; |
| const AABB kRect(l, t, r, b); |
| PathBuilder builder; |
| switch (type) |
| { |
| case kCircle_ShapeType: |
| builder.addOval(kRect); |
| break; |
| case kRoundRect_ShapeType: |
| builder.addRRect(kRect, 15.f, 15.f); |
| break; |
| case kRect_ShapeType: |
| builder.addRect(kRect); |
| break; |
| case kConvexPath_ShapeType: |
| { |
| builder.moveTo(l, t); |
| builder.quadTo(r, t, r, b); |
| builder.quadTo(l, b, l, t); |
| break; |
| } |
| case kPolygonFan_ShapeType: |
| { |
| float a0 = 0, a1 = 2 * math::PI / 3, a2 = 4 * math::PI / 3, |
| a3 = 2 * math::PI; |
| float x = (l + r) / 2, y = (t + b) / 2; |
| float rx = (r - l) / 2, ry = (b - t) / 2; |
| builder.moveTo(cosf(a0) * rx + x, sinf(a0) * ry + y); |
| builder.lineTo(cosf(a1) * rx + x, sinf(a1) * ry + y); |
| builder.lineTo(cosf(a2) * rx + x, sinf(a2) * ry + y); |
| builder.lineTo(cosf(a3) * rx + x, sinf(a3) * ry + y); |
| builder.close(); |
| fan_polygon(builder, a0, a1, x, y, rx, ry, 5); |
| fan_polygon(builder, a1, a2, x, y, rx, ry, 5); |
| fan_polygon(builder, a2, a3, x, y, rx, ry, 5); |
| break; |
| } |
| case kConcavePath_ShapeType: |
| { |
| Vec2D points[5] = { |
| {70.f * cosf(-math::PI / 2), 70.f * sinf(-math::PI / 2)}}; |
| Mat2D rot = Mat2D::fromRotation(2 * math::PI / 5); |
| for (int i = 1; i < 5; ++i) |
| { |
| rot.mapPoints(points + i, points + i - 1, 1); |
| } |
| builder.moveTo(points[0].x + 50, points[0].y + 70); |
| for (int i = 0; i < 5; ++i) |
| { |
| auto [x, y] = points[(2 * i) % 5]; |
| builder.lineTo(x + 50, y + 70); |
| } |
| builder.fillRule(FillRule::evenOdd); |
| break; |
| } |
| default: |
| break; |
| } |
| renderer->drawPath(builder.detach(), paint); |
| } |
| |
| static ColorInt GetColor(Rand* random) |
| { |
| return 0x80000000 | (random->u32() & 0xffffff); |
| } |
| |
| // static void DrawHairlines(Renderer* renderer) { |
| // if (canvas->imageInfo().alphaType() == kOpaque_SkAlphaType) { |
| // draw_clear(renderer, kBackground); |
| // } else { |
| // canvas->clear(SK_ColorTRANSPARENT); |
| // } |
| // SkPaint hairPaint; |
| // hairPaint.setStyle(SkPaint::kStroke_Style); |
| // hairPaint.setStrokeWidth(0); |
| // hairPaint.setAntiAlias(true); |
| // static constexpr int kNumHairlines = 12; |
| // SkPoint pts[] = {{3.f, 7.f}, {29.f, 7.f}}; |
| // Rand colorRandom; |
| // SkMatrix rot; |
| // rot.setRotate(360.f / kNumHairlines, 15.5f, 12.f); |
| // rot.postTranslate(3.f, 0); |
| // for (int i = 0; i < 12; ++i) { |
| // hairPaint.setColor(GetColor(&colorRandom)); |
| // canvas->drawLine(pts[0], pts[1], hairPaint); |
| // rot.mapPoints(pts, 2); |
| // } |
| // } |
| |
| void onDraw(Renderer* renderer) override |
| { |
| Paint p; |
| p->color(0x80808080); |
| draw_rect(renderer, {0, 0, 530, 690}, p); |
| |
| float y = 5; |
| for (int i = 0; i < kNumShapeTypes; i++) |
| { |
| Rand colorRandom; |
| ShapeType shapeType = static_cast<ShapeType>(i); |
| float x = 5; |
| for (int r = 0; r <= 15; r++) |
| { |
| Paint p; |
| p->color(GetColor(&colorRandom)); |
| // In order to get some op combining on the GPU backend we do 2 |
| // src over for each xfer mode which requires a dst read |
| constexpr static BlendMode blendModes[] = { |
| BlendMode::srcOver, |
| BlendMode::screen, |
| BlendMode::overlay, |
| BlendMode::darken, |
| BlendMode::lighten, |
| BlendMode::colorDodge, |
| BlendMode::colorBurn, |
| BlendMode::hardLight, |
| BlendMode::softLight, |
| BlendMode::exclusion, |
| BlendMode::hue, |
| BlendMode::saturation, |
| BlendMode::color, |
| BlendMode::luminosity, |
| }; |
| p->blendMode(blendModes[r % std::size(blendModes)]); |
| renderer->save(); |
| renderer->translate(x, y); |
| this->drawShape(renderer, p, shapeType); |
| renderer->restore(); |
| x += 15; |
| } |
| y += 110; |
| } |
| // // Draw hairlines to a surface and then draw that to the main canvas |
| // with a zoom so that |
| // // it is easier to see how they blend. |
| // SkImageInfo info; |
| // // Recording canvases don't have a color type. |
| // if (SkColorType::kUnknown_SkColorType == |
| // canvas->imageInfo().colorType()) { |
| // info = SkImageInfo::MakeN32Premul(35, 35); |
| // } else { |
| // info = SkImageInfo::Make(35, 35, |
| // canvas->imageInfo().colorType(), |
| // canvas->imageInfo().alphaType(), |
| // canvas->imageInfo().refColorSpace()); |
| // } |
| // auto surf = canvas->makeSurface(info); |
| // if (!surf) { |
| // // Fall back to raster. Raster supports only one of the 8 bit |
| // per-channel RGBA or BGRA |
| // // formats. This fall back happens when running with |
| // --preAbandonGpuContext. if ((info.colorType() == |
| // kRGBA_8888_SkColorType || |
| // info.colorType() == kBGRA_8888_SkColorType) && |
| // info.colorType() != kN32_SkColorType) { |
| // info = SkImageInfo::Make(35, 35, |
| // kN32_SkColorType, |
| // canvas->imageInfo().alphaType(), |
| // canvas->imageInfo().refColorSpace()); |
| // } |
| // surf = SkSurface::MakeRaster(info); |
| // SkASSERT(surf); |
| // } |
| // canvas->scale(5.f, 5.f); |
| // canvas->translate(67.f, 10.f); |
| // DrawHairlines(surf->getCanvas()); |
| // canvas->drawImage(surf->makeImageSnapshot(), 0.f, 0.f); |
| } |
| |
| private: |
| static constexpr ColorInt kBackground = 0xFFCCCCCC; |
| using INHERITED = GM; |
| }; |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| GMREGISTER(dstreadshuffle, return new DstReadShuffle;) |