| #include "rive/shapes/paint/shape_paint.hpp" | |
| #include "rive/shapes/shape_paint_container.hpp" | |
| #include "rive/shapes/paint/feather.hpp" | |
| #include "rive/artboard.hpp" | |
| #include "rive/factory.hpp" | |
| #include "rive/shapes/paint/fill.hpp" | |
| using namespace rive; | |
| StatusCode ShapePaint::onAddedClean(CoreContext* context) | |
| { | |
| auto container = ShapePaintContainer::from(parent()); | |
| if (container == nullptr) | |
| { | |
| return StatusCode::MissingObject; | |
| } | |
| // If the paint mutator wasn't compatible with this runtime it's possible we | |
| // get a ShapePaint with no mutator (not children). | |
| if (m_PaintMutator != nullptr) | |
| { | |
| container->addPaint(this); | |
| } | |
| return StatusCode::Ok; | |
| } | |
| RenderPaint* ShapePaint::initRenderPaint(ShapePaintMutator* mutator) | |
| { | |
| assert(m_RenderPaint == nullptr); | |
| m_PaintMutator = mutator; | |
| auto factory = mutator->component()->artboard()->factory(); | |
| m_RenderPaint = factory->makeRenderPaint(); | |
| return m_RenderPaint.get(); | |
| } | |
| void ShapePaint::blendMode(BlendMode parentValue) | |
| { | |
| assert(m_RenderPaint != nullptr); | |
| // 127 means inherit | |
| if (blendModeValue() == 127) | |
| { | |
| m_RenderPaint->blendMode(parentValue); | |
| } | |
| else | |
| { | |
| m_RenderPaint->blendMode((BlendMode)blendModeValue()); | |
| } | |
| } | |
| void ShapePaint::feather(Feather* feather) { m_feather = feather; } | |
| Feather* ShapePaint::feather() const { return m_feather; } | |
| void ShapePaint::draw(Renderer* renderer, | |
| ShapePaintPath* shapePaintPath, | |
| const Mat2D& transform, | |
| bool usePathFillRule, | |
| RenderPaint* overridePaint) | |
| { | |
| ShapePaintPath* pathToDraw = shapePaintPath; | |
| bool saved = false; | |
| if (m_feather != nullptr) | |
| { | |
| bool offsetInArtboard = m_feather->space() == TransformSpace::world; | |
| if (offsetInArtboard && !m_feather->inner()) | |
| { | |
| if (m_feather->offsetX() != 0 || m_feather->offsetY() != 0) | |
| { | |
| if (!saved) | |
| { | |
| saved = true; | |
| renderer->save(); | |
| } | |
| renderer->translate(m_feather->offsetX(), m_feather->offsetY()); | |
| } | |
| } | |
| } | |
| if (shapePaintPath->isLocal()) | |
| { | |
| if (!saved) | |
| { | |
| saved = true; | |
| renderer->save(); | |
| } | |
| renderer->transform(transform); | |
| } | |
| if (m_feather != nullptr) | |
| { | |
| if (m_feather->inner()) | |
| { | |
| if (m_feather->innerPath() == nullptr) | |
| { | |
| return; | |
| } | |
| pathToDraw = m_feather->innerPath(); | |
| if (!saved) | |
| { | |
| saved = true; | |
| renderer->save(); | |
| } | |
| auto renderPath = shapePaintPath->renderPath(this); | |
| if (renderPath != nullptr) | |
| { | |
| renderer->clipPath(renderPath); | |
| } | |
| } | |
| // If we're offseting in world space, apply the offset last. | |
| if (m_feather->space() != TransformSpace::world && | |
| !m_feather->inner() && | |
| (m_feather->offsetX() != 0 || m_feather->offsetY() != 0)) | |
| { | |
| if (!saved) | |
| { | |
| saved = true; | |
| renderer->save(); | |
| } | |
| renderer->translate(m_feather->offsetX(), m_feather->offsetY()); | |
| } | |
| } | |
| auto renderPath = pathToDraw->renderPath(this); | |
| if (renderPath != nullptr) | |
| { | |
| // Ugh, can't we make fillRule part of the Paint? | |
| if (!usePathFillRule && is<Fill>()) | |
| { | |
| renderPath->fillRule((FillRule)as<Fill>()->fillRule()); | |
| } | |
| renderer->drawPath(renderPath, | |
| overridePaint != nullptr ? overridePaint | |
| : renderPaint()); | |
| } | |
| if (saved) | |
| { | |
| renderer->restore(); | |
| } | |
| } |