| #include "rive/nested_artboard.hpp" |
| #include "rive/artboard.hpp" |
| #include "rive/backboard.hpp" |
| #include "rive/importers/import_stack.hpp" |
| #include "rive/importers/backboard_importer.hpp" |
| #include "rive/nested_animation.hpp" |
| |
| using namespace rive; |
| |
| NestedArtboard::NestedArtboard() {} |
| NestedArtboard::~NestedArtboard() {} |
| |
| Core* NestedArtboard::clone() const { |
| NestedArtboard* nestedArtboard = static_cast<NestedArtboard*>(NestedArtboardBase::clone()); |
| if (m_Artboard == nullptr) { |
| return nestedArtboard; |
| } |
| auto ni = m_Artboard->instance(); |
| nestedArtboard->nest(ni.release()); |
| return nestedArtboard; |
| } |
| |
| void NestedArtboard::nest(Artboard* artboard) { |
| assert(artboard != nullptr); |
| |
| m_Artboard = artboard; |
| m_Instance = nullptr; |
| if (artboard->isInstance()) { |
| m_Instance.reset(static_cast<ArtboardInstance*>(artboard)); // take ownership |
| } |
| m_Artboard->advance(0.0f); |
| } |
| |
| static Mat2D makeTranslate(const Artboard* artboard) { |
| return Mat2D::fromTranslate(-artboard->originX() * artboard->width(), |
| -artboard->originY() * artboard->height()); |
| } |
| |
| void NestedArtboard::draw(Renderer* renderer) { |
| if (m_Artboard == nullptr) { |
| return; |
| } |
| if (!clip(renderer)) { |
| // We didn't clip, so make sure to save as we'll be doing some |
| // transformations. |
| renderer->save(); |
| } |
| renderer->transform(worldTransform() * makeTranslate(m_Artboard)); |
| m_Artboard->draw(renderer); |
| renderer->restore(); |
| } |
| |
| Core* NestedArtboard::hitTest(HitInfo* hinfo, const Mat2D& xform) { |
| if (m_Artboard == nullptr) { |
| return nullptr; |
| } |
| hinfo->mounts.push_back(this); |
| auto mx = xform * worldTransform() * makeTranslate(m_Artboard); |
| if (auto c = m_Artboard->hitTest(hinfo, &mx)) { |
| return c; |
| } |
| hinfo->mounts.pop_back(); |
| return nullptr; |
| } |
| |
| StatusCode NestedArtboard::import(ImportStack& importStack) { |
| auto backboardImporter = importStack.latest<BackboardImporter>(Backboard::typeKey); |
| if (backboardImporter == nullptr) { |
| return StatusCode::MissingObject; |
| } |
| backboardImporter->addNestedArtboard(this); |
| |
| return Super::import(importStack); |
| } |
| |
| void NestedArtboard::addNestedAnimation(NestedAnimation* nestedAnimation) { |
| m_NestedAnimations.push_back(nestedAnimation); |
| } |
| |
| StatusCode NestedArtboard::onAddedClean(CoreContext* context) { |
| // N.B. The nested instance will be null here for the source artboards. |
| // Instances will have a nestedInstance available. This is a good thing as |
| // it ensures that we only instance animations in artboard instances. It |
| // does require that we always use an artboard instance (not just the source |
| // artboard) when working with nested artboards, but in general this is good |
| // practice for any loaded Rive file. |
| assert(m_Artboard == nullptr || m_Artboard == m_Instance.get()); |
| |
| if (m_Instance) { |
| for (auto animation : m_NestedAnimations) { |
| animation->initializeAnimation(m_Instance.get()); |
| } |
| } |
| return Super::onAddedClean(context); |
| } |
| |
| bool NestedArtboard::advance(float elapsedSeconds) { |
| if (m_Artboard == nullptr) { |
| return false; |
| } |
| for (auto animation : m_NestedAnimations) { |
| animation->advance(elapsedSeconds); |
| } |
| return m_Artboard->advance(elapsedSeconds); |
| } |
| |
| void NestedArtboard::update(ComponentDirt value) { |
| Super::update(value); |
| if (hasDirt(value, ComponentDirt::WorldTransform) && m_Artboard != nullptr) { |
| m_Artboard->opacity(renderOpacity()); |
| } |
| } |