void RotateCommand::onExecute(Context* context) { ContextReader reader(context); { CelList cels; bool rotateSprite = false; // Flip the mask or current cel if (m_flipMask) { DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range(); if (range.enabled()) cels = get_unique_cels(reader.sprite(), range); else if (reader.cel()) cels.push_back(reader.cel()); } // Flip the whole sprite else if (reader.sprite()) { for (Cel* cel : reader.sprite()->uniqueCels()) cels.push_back(cel); rotateSprite = true; } if (cels.empty()) // Nothing to do return; RotateJob job(reader, m_angle, cels, rotateSprite); job.startJob(); job.waitJob(); } reader.document()->generateMaskBoundaries(); update_screen_for_document(reader.document()); }
void RotateCommand::onExecute(Context* context) { { Site site = context->activeSite(); CelList cels; bool rotateSprite = false; // Flip the mask or current cel if (m_flipMask) { auto range = App::instance()->timeline()->range(); if (range.enabled()) cels = get_unique_cels(site.sprite(), range); else if (site.cel()) { // If we want to rotate the visible mask for the current cel, // we can go to MovingPixelsState. if (static_cast<app::Document*>(site.document())->isMaskVisible()) { // Select marquee tool if (tools::Tool* tool = App::instance()->toolBox() ->getToolById(tools::WellKnownTools::RectangularMarquee)) { ToolBar::instance()->selectTool(tool); current_editor->startSelectionTransformation(gfx::Point(0, 0), m_angle); return; } } cels.push_back(site.cel()); } } // Flip the whole sprite else if (site.sprite()) { for (Cel* cel : site.sprite()->uniqueCels()) cels.push_back(cel); rotateSprite = true; } if (cels.empty()) // Nothing to do return; ContextReader reader(context); { RotateJob job(reader, m_angle, cels, rotateSprite); job.startJob(); job.waitJob(); } reader.document()->generateMaskBoundaries(); update_screen_for_document(reader.document()); } }
void LayerImage::getCels(CelList& cels) const { CelConstIterator it = getCelBegin(); CelConstIterator end = getCelEnd(); for (; it != end; ++it) cels.push_back(*it); }
void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const { std::vector<Layer*> layers; getLayersList(layers); for (int i=(int)layers.size()-1; i>=0; --i) { Layer* layer = layers[i]; if (!layer->isImage() || !layer->isVisible()) continue; Cel* cel = layer->cel(frame); if (!cel) continue; Image* image = cel->image(); if (!image) continue; if (!cel->bounds().contains(gfx::Point(x, y))) continue; color_t color = get_pixel(image, x - cel->x(), y - cel->y()); bool isOpaque = true; switch (image->pixelFormat()) { case IMAGE_RGB: isOpaque = (rgba_geta(color) >= opacityThreshold); break; case IMAGE_INDEXED: isOpaque = (color != image->maskColor()); break; case IMAGE_GRAYSCALE: isOpaque = (graya_geta(color) >= opacityThreshold); break; } if (!isOpaque) continue; cels.push_back(cel); } fflush(stdout); }
// TODO the DocumentRange should be "iteratable" to replace this function CelList get_cels_in_range(Sprite* sprite, const DocumentRange& range) { CelList cels; for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) { Layer* layer = sprite->indexToLayer(layerIdx); if (!layer->isImage()) continue; LayerImage* layerImage = static_cast<LayerImage*>(layer); for (FrameNumber frame = range.frameEnd(), begin = range.frameBegin().previous(); frame != begin; frame = frame.previous()) { Cel* cel = layerImage->getCel(frame); if (cel) cels.push_back(cel); } } return cels; }
void FlipCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); { Transaction transaction(writer.context(), m_flipMask ? (m_flipType == doc::algorithm::FlipHorizontal ? "Flip Horizontal": "Flip Vertical"): (m_flipType == doc::algorithm::FlipHorizontal ? "Flip Canvas Horizontal": "Flip Canvas Vertical")); DocumentApi api = document->getApi(transaction); CelList cels; if (m_flipMask) { auto range = App::instance()->timeline()->range(); if (range.enabled()) cels = get_unique_cels(sprite, range); else if (writer.cel()) cels.push_back(writer.cel()); } else { for (Cel* cel : sprite->uniqueCels()) cels.push_back(cel); } Mask* mask = document->mask(); if (m_flipMask && document->isMaskVisible()) { Site site = *writer.site(); for (Cel* cel : cels) { site.frame(cel->frame()); site.layer(cel->layer()); int x, y; Image* image = site.image(&x, &y); if (!image) continue; // When the mask is inside the cel, we can try to flip the // pixels inside the image. if (cel->bounds().contains(mask->bounds())) { gfx::Rect flipBounds = mask->bounds(); flipBounds.offset(-x, -y); flipBounds &= image->bounds(); if (flipBounds.isEmpty()) continue; if (mask->bitmap() && !mask->isRectangular()) transaction.execute(new cmd::FlipMaskedCel(cel, m_flipType)); else api.flipImage(image, flipBounds, m_flipType); if (cel->layer()->isTransparent()) transaction.execute(new cmd::TrimCel(cel)); } // When the mask is bigger than the cel bounds, we have to // expand the cel, make the flip, and shrink it again. else { gfx::Rect flipBounds = (sprite->bounds() & mask->bounds()); if (flipBounds.isEmpty()) continue; ExpandCelCanvas expand( site, cel->layer(), TiledMode::NONE, transaction, ExpandCelCanvas::None); expand.validateDestCanvas(gfx::Region(flipBounds)); if (mask->bitmap() && !mask->isRectangular()) doc::algorithm::flip_image_with_mask( expand.getDestCanvas(), mask, m_flipType, document->bgColor(cel->layer())); else doc::algorithm::flip_image( expand.getDestCanvas(), flipBounds, m_flipType); expand.commit(); } } } else { for (Cel* cel : cels) { Image* image = cel->image(); api.setCelPosition (sprite, cel, (m_flipType == doc::algorithm::FlipHorizontal ? sprite->width() - image->width() - cel->x(): cel->x()), (m_flipType == doc::algorithm::FlipVertical ? sprite->height() - image->height() - cel->y(): cel->y())); api.flipImage(image, image->bounds(), m_flipType); } } // Flip the mask. Image* maskBitmap = mask->bitmap(); if (maskBitmap) { transaction.execute(new cmd::FlipMask(document, m_flipType)); // Flip the mask position because the if (!m_flipMask) transaction.execute( new cmd::SetMaskPosition( document, gfx::Point( (m_flipType == doc::algorithm::FlipHorizontal ? sprite->width() - mask->bounds().x2(): mask->bounds().x), (m_flipType == doc::algorithm::FlipVertical ? sprite->height() - mask->bounds().y2(): mask->bounds().y)))); document->generateMaskBoundaries(); } transaction.commit(); } update_screen_for_document(document); }
void FilterManagerImpl::applyToTarget() { const bool paletteChange = paletteHasChanged(); bool cancelled = false; CelList cels; switch (m_celsTarget) { case CelsTarget::Selected: { auto range = App::instance()->timeline()->range(); if (range.enabled()) cels = get_unlocked_unique_cels(m_site.sprite(), range); else if (m_site.cel() && m_site.layer() && m_site.layer()->isEditable()) { cels.push_back(m_site.cel()); } break; } case CelsTarget::All: { for (Cel* cel : m_site.sprite()->uniqueCels()) { if (cel->layer()->isEditable()) cels.push_back(cel); } break; } } if (cels.empty() && !paletteChange) { // We don't have images/palette changes to do (there will not be a // transaction). return; } // Initialize writting operation ContextReader reader(m_context); ContextWriter writer(reader); m_transaction.reset(new Transaction(writer.context(), m_filter->getName(), ModifyDocument)); m_progressBase = 0.0f; m_progressWidth = (cels.size() > 0 ? 1.0f / cels.size(): 1.0f); std::set<ObjectId> visited; // Palette change if (paletteChange) { Palette newPalette = *getNewPalette(); restoreSpritePalette(); m_transaction->execute( new cmd::SetPalette(m_site.sprite(), m_site.frame(), &newPalette)); } // For each target image for (auto it = cels.begin(); it != cels.end() && !cancelled; ++it) { Image* image = (*it)->image(); // Avoid applying the filter two times to the same image if (visited.find(image->id()) == visited.end()) { visited.insert(image->id()); applyToCel(*it); } // Is there a delegate to know if the process was cancelled by the user? if (m_progressDelegate) cancelled = m_progressDelegate->isCancelled(); // Make progress m_progressBase += m_progressWidth; } // Reset m_oldPalette to avoid restoring the color palette m_oldPalette.reset(nullptr); }