ExpandCelCanvas::ExpandCelCanvas(DocumentLocation location, TiledMode tiledMode, Transaction& transaction, Flags flags) : m_document(location.document()) , m_sprite(location.sprite()) , m_layer(location.layer()) , m_cel(NULL) , m_celImage(NULL) , m_celCreated(false) , m_flags(flags) , m_srcImage(NULL) , m_dstImage(NULL) , m_closed(false) , m_committed(false) , m_transaction(transaction) { create_buffers(); if (m_layer->isImage()) { m_cel = m_layer->cel(location.frame()); if (m_cel) m_celImage = m_cel->imageRef(); } // Create a new cel if (m_cel == NULL) { m_celCreated = true; m_cel = new Cel(location.frame(), ImageRef(NULL)); } m_origCelPos = m_cel->position(); // Region to draw gfx::Rect celBounds( m_cel->x(), m_cel->y(), m_celImage ? m_celImage->width(): m_sprite->width(), m_celImage ? m_celImage->height(): m_sprite->height()); gfx::Rect spriteBounds(0, 0, m_sprite->width(), m_sprite->height()); if (tiledMode == TiledMode::NONE) { // Non-tiled m_bounds = celBounds.createUnion(spriteBounds); } else { // Tiled m_bounds = spriteBounds; } // We have to adjust the cel position to match the m_dstImage // position (the new m_dstImage will be used in RenderEngine to // draw this cel). m_cel->setPosition(m_bounds.x, m_bounds.y); if (m_celCreated) { getDestCanvas(); m_cel->data()->setImage(m_dstImage); static_cast<LayerImage*>(m_layer)->addCel(m_cel); } }
void ExpandCelCanvas::validateDestCanvas(const gfx::Region& rgn) { Image* src; int src_x, src_y; if ((m_flags & NeedsSource) == NeedsSource) { validateSourceCanvas(rgn); src = m_srcImage.get(); src_x = m_bounds.x; src_y = m_bounds.y; } else { src = m_celImage.get(); src_x = m_origCelPos.x; src_y = m_origCelPos.y; } getDestCanvas(); gfx::Region rgnToValidate(rgn); rgnToValidate.offset(-m_bounds.origin()); rgnToValidate.createSubtraction(rgnToValidate, m_validDstRegion); rgnToValidate.createIntersection(rgnToValidate, gfx::Region(m_dstImage->bounds())); if (src) { gfx::Region rgnToClear; rgnToClear.createSubtraction(rgnToValidate, gfx::Region(src->bounds() .offset(src_x, src_y) .offset(-m_bounds.origin()))); for (const auto& rc : rgnToClear) fill_rect(m_dstImage.get(), rc, m_dstImage->maskColor()); for (const auto& rc : rgnToValidate) m_dstImage->copy(src, gfx::Clip(rc.x, rc.y, rc.x+m_bounds.x-src_x, rc.y+m_bounds.y-src_y, rc.w, rc.h)); } else { for (const auto& rc : rgnToValidate) fill_rect(m_dstImage.get(), rc, m_dstImage->maskColor()); } m_validDstRegion.createUnion(m_validDstRegion, rgnToValidate); }
ExpandCelCanvas::ExpandCelCanvas( Site site, Layer* layer, TiledMode tiledMode, Transaction& transaction, Flags flags) : m_document(static_cast<app::Document*>(site.document())) , m_sprite(site.sprite()) , m_layer(layer) , m_frame(site.frame()) , m_cel(NULL) , m_celImage(NULL) , m_celCreated(false) , m_flags(flags) , m_srcImage(NULL) , m_dstImage(NULL) , m_closed(false) , m_committed(false) , m_transaction(transaction) , m_canCompareSrcVsDst((m_flags & NeedsSource) == NeedsSource) { ASSERT(!singleton); singleton = this; create_buffers(); if (m_layer && m_layer->isImage()) { m_cel = m_layer->cel(site.frame()); if (m_cel) m_celImage = m_cel->imageRef(); } // Create a new cel if (!m_cel) { m_celCreated = true; m_cel = new Cel(site.frame(), ImageRef(NULL)); } m_origCelPos = m_cel->position(); // Region to draw gfx::Rect celBounds( m_cel->x(), m_cel->y(), m_celImage ? m_celImage->width(): m_sprite->width(), m_celImage ? m_celImage->height(): m_sprite->height()); gfx::Rect spriteBounds(0, 0, m_sprite->width(), m_sprite->height()); if (tiledMode == TiledMode::NONE) { // Non-tiled m_bounds = celBounds.createUnion(spriteBounds); } else { // Tiled m_bounds = spriteBounds; } // We have to adjust the cel position to match the m_dstImage // position (the new m_dstImage will be used in RenderEngine to // draw this cel). m_cel->setPosition(m_bounds.x, m_bounds.y); if (m_celCreated) { getDestCanvas(); m_cel->data()->setImage(m_dstImage); if (m_layer && m_layer->isImage()) static_cast<LayerImage*>(m_layer)->addCel(m_cel); } }
void ExpandCelCanvas::commit() { ASSERT(!m_closed); ASSERT(!m_committed); if (!m_layer) { m_committed = true; return; } // Was the cel created in the start of the tool-loop? if (m_celCreated) { ASSERT(m_cel); ASSERT(!m_celImage); // Validate the whole m_dstImage (invalid areas are cleared, as we // don't have a m_celImage) validateDestCanvas(gfx::Region(m_bounds)); // We can temporary remove the cel. if (m_layer->isImage()) { static_cast<LayerImage*>(m_layer)->removeCel(m_cel); // Add a copy of m_dstImage in the sprite's image stock gfx::Rect trimBounds = getTrimDstImageBounds(); if (!trimBounds.isEmpty()) { ImageRef newImage(trimDstImage(trimBounds)); ASSERT(newImage); m_cel->data()->setImage(newImage); m_cel->setPosition(m_cel->position() + trimBounds.origin()); // And finally we add the cel again in the layer. m_transaction.execute(new cmd::AddCel(m_layer, m_cel)); } } // We are selecting inside a layer group... else { // Just delete the created layer delete m_cel; m_cel = nullptr; } } else if (m_celImage) { // Restore cel position to its original position m_cel->setPosition(m_origCelPos); ASSERT(m_cel->image() == m_celImage.get()); gfx::Region* regionToPatch = &m_validDstRegion; gfx::Region reduced; if (m_canCompareSrcVsDst) { ASSERT(gfx::Region().createSubtraction(m_validDstRegion, m_validSrcRegion).isEmpty()); for (gfx::Rect rc : m_validDstRegion) { if (algorithm::shrink_bounds2(getSourceCanvas(), getDestCanvas(), rc, rc)) { reduced |= gfx::Region(rc); } } regionToPatch = &reduced; } if (m_layer->isBackground()) { m_transaction.execute( new cmd::CopyRegion( m_cel->image(), m_dstImage.get(), *regionToPatch, m_bounds.origin())); } else { m_transaction.execute( new cmd::PatchCel( m_cel, m_dstImage.get(), *regionToPatch, m_bounds.origin())); } } else { ASSERT(false); } m_committed = true; }