void Sprite::remapImages(FrameNumber frameFrom, FrameNumber frameTo, const std::vector<uint8_t>& mapping) { ASSERT(m_format == IMAGE_INDEXED); ASSERT(mapping.size() == 256); CelList cels; getCels(cels); for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; // Remap this Cel because is inside the specified range if (cel->getFrame() >= frameFrom && cel->getFrame() <= frameTo) { Image* image = getStock()->getImage(cel->getImage()); LockImageBits<IndexedTraits> bits(image); LockImageBits<IndexedTraits>::iterator it = bits.begin(), end = bits.end(); for (; it != end; ++it) *it = mapping[*it]; } } }
size_t Sprite::getImageRefs(int imageIndex) const { CelList cels; getCels(cels); size_t refs = 0; for (CelList::iterator it=cels.begin(), end=cels.end(); it != end; ++it) if ((*it)->getImage() == imageIndex) ++refs; return refs; }
void Sprite::remapImages(FrameNumber frameFrom, FrameNumber frameTo, const std::vector<uint8_t>& mapping) { ASSERT(m_format == IMAGE_INDEXED); ASSERT(mapping.size() == 256); CelList cels; getCels(cels); for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; // Remap this Cel because is inside the specified range if (cel->getFrame() >= frameFrom && cel->getFrame() <= frameTo) { Image* image = getStock()->getImage(cel->getImage()); for (int y=0; y<image->h; ++y) { IndexedTraits::address_t ptr = image_address_fast<IndexedTraits>(image, 0, y); for (int x=0; x<image->w; ++x, ++ptr) *ptr = mapping[*ptr]; } } } }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas"); DocumentApi api = m_document->getApi(); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: api.setCelPosition(m_sprite, cel, m_sprite->getWidth() - cel->getX() - image->getWidth(), m_sprite->getHeight() - cel->getY() - image->getHeight()); break; case 90: api.setCelPosition(m_sprite, cel, m_sprite->getHeight() - cel->getY() - image->getHeight(), cel->getX()); break; case -90: api.setCelPosition(m_sprite, cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->getWidth()); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = Image::create(image->getPixelFormat(), m_angle == 180 ? image->getWidth(): image->getHeight(), m_angle == 180 ? image->getHeight(): image->getWidth()); raster::rotate_image(image, new_image, m_angle); api.replaceStockImage(m_sprite, i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); base::UniquePtr<Mask> new_mask(new Mask()); const gfx::Rect& origBounds = origMask->getBounds(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origBounds.x - origBounds.w; y = m_sprite->getHeight() - origBounds.y - origBounds.h; break; case 90: x = m_sprite->getHeight() - origBounds.y - origBounds.h; y = origBounds.x; break; case -90: x = origBounds.y; y = m_sprite->getWidth() - origBounds.x - origBounds.w; break; } // create the new rotated mask new_mask->replace(x, y, m_angle == 180 ? origBounds.w: origBounds.h, m_angle == 180 ? origBounds.h: origBounds.w); raster::rotate_image(origMask->getBitmap(), new_mask->getBitmap(), m_angle); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) api.setSpriteSize(m_sprite, m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_document, "Rotate Canvas"); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: undoTransaction.setCelPosition(cel, m_sprite->getWidth() - cel->getX() - image->w, m_sprite->getHeight() - cel->getY() - image->h); break; case 90: undoTransaction.setCelPosition(cel, m_sprite->getHeight() - cel->getY() - image->h, cel->getX()); break; case -90: undoTransaction.setCelPosition(cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->w); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = image_new(image->imgtype, m_angle == 180 ? image->w: image->h, m_angle == 180 ? image->h: image->w); image_rotate(image, new_image, m_angle); undoTransaction.replaceStockImage(i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); Mask* new_mask = mask_new(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origMask->x - origMask->w; y = m_sprite->getHeight() - origMask->y - origMask->h; break; case 90: x = m_sprite->getHeight() - origMask->y - origMask->h; y = origMask->x; break; case -90: x = origMask->y; y = m_sprite->getWidth() - origMask->x - origMask->w; break; } // create the new rotated mask mask_replace(new_mask, x, y, m_angle == 180 ? origMask->w: origMask->h, m_angle == 180 ? origMask->h: origMask->w); image_rotate(origMask->bitmap, new_mask->bitmap, m_angle); // copy new mask undoTransaction.copyToCurrentMask(new_mask); mask_free(new_mask); // regenerate mask m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) undoTransaction.setSpriteSize(m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
void FlipCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); DocumentApi api = document->getApi(); { UndoTransaction undoTransaction(writer.context(), m_flipMask ? (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Horizontal": "Flip Vertical"): (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Canvas Horizontal": "Flip Canvas Vertical")); if (m_flipMask) { int x, y; Image* image = writer.image(&x, &y); if (!image) return; Mask* mask = NULL; bool alreadyFlipped = false; // This variable will be the area to be flipped inside the image. gfx::Rect bounds(image->getBounds()); // If there is some portion of sprite selected, we flip the // selected region only. If the mask isn't visible, we flip the // whole image. if (document->isMaskVisible()) { mask = document->getMask(); // Intersect the full area of the image with the mask's // bounds, so we don't request to flip an area outside the // image's bounds. bounds = bounds.createIntersect(gfx::Rect(mask->getBounds()).offset(-x, -y)); // If the mask isn't a rectangular area, we've to flip the mask too. if (mask->getBitmap() != NULL && !mask->isRectangular()) { int bgcolor = app_get_color_to_clear_layer(writer.layer()); // Flip the portion of image specified by the mask. mask->offsetOrigin(-x, -y); api.flipImageWithMask(image, mask, m_flipType, bgcolor); mask->offsetOrigin(x, y); alreadyFlipped = true; // Flip the mask. Image* maskBitmap = mask->getBitmap(); if (maskBitmap != NULL) { // Create a flipped copy of the current mask. base::UniquePtr<Mask> newMask(new Mask(*mask)); newMask->freeze(); raster::algorithm::flip_image(newMask->getBitmap(), maskBitmap->getBounds(), m_flipType); newMask->unfreeze(); // Change the current mask and generate the new boundaries. api.copyToCurrentMask(newMask); document->generateMaskBoundaries(); } } } // Flip the portion of image specified by "bounds" variable. if (!alreadyFlipped) { api.flipImage(image, bounds, m_flipType); } } else { // get all sprite cels CelList cels; sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = sprite->getStock()->getImage(cel->getImage()); api.setCelPosition (sprite, cel, (m_flipType == raster::algorithm::FlipHorizontal ? sprite->getWidth() - image->getWidth() - cel->getX(): cel->getX()), (m_flipType == raster::algorithm::FlipVertical ? sprite->getHeight() - image->getHeight() - cel->getY(): cel->getY())); api.flipImage(image, image->getBounds(), m_flipType); } } undoTransaction.commit(); } update_screen_for_document(document); }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_writer.context(), "Sprite Size"); DocumentApi api = m_writer.document()->getApi(); // Get all sprite cels CelList cels; m_sprite->getCels(cels); // For each cel... int progress = 0; for (CelIterator it = cels.begin(); it != cels.end(); ++it, ++progress) { Cel* cel = *it; // Change its location api.setCelPosition(m_sprite, cel, scale_x(cel->x()), scale_y(cel->y())); // Get cel's image Image* image = cel->image(); if (!image) continue; // Resize the image int w = scale_x(image->width()); int h = scale_y(image->height()); Image* new_image = Image::create(image->pixelFormat(), MAX(1, w), MAX(1, h)); doc::algorithm::fixup_image_transparent_colors(image); doc::algorithm::resize_image(image, new_image, m_resize_method, m_sprite->getPalette(cel->frame()), m_sprite->getRgbMap(cel->frame())); api.replaceStockImage(m_sprite, cel->imageIndex(), new_image); jobProgress((float)progress / cels.size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // Resize mask if (m_document->isMaskVisible()) { base::UniquePtr<Image> old_bitmap (crop_image(m_document->mask()->bitmap(), -1, -1, m_document->mask()->bitmap()->width()+2, m_document->mask()->bitmap()->height()+2, 0)); int w = scale_x(old_bitmap->width()); int h = scale_y(old_bitmap->height()); base::UniquePtr<Mask> new_mask(new Mask); new_mask->replace(scale_x(m_document->mask()->bounds().x-1), scale_y(m_document->mask()->bounds().y-1), MAX(1, w), MAX(1, h)); algorithm::resize_image(old_bitmap, new_mask->bitmap(), m_resize_method, m_sprite->getPalette(FrameNumber(0)), // Ignored m_sprite->getRgbMap(FrameNumber(0))); // Ignored // Reshrink new_mask->intersect(new_mask->bounds()); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // resize sprite api.setSpriteSize(m_sprite, m_new_width, m_new_height); // commit changes undoTransaction.commit(); }
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); }