mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-31 09:32:49 +00:00
Add support to flip irregular selections.
- Added raster::algorithm::flip_image_with_mask() function. - Added UndoTransaction::flipImageWithMask() member function. - Added Mask::isRectangular() member function.
This commit is contained in:
parent
cd8e92ce18
commit
3422b82bc4
src
@ -18,6 +18,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "commands/command.h"
|
||||
#include "commands/params.h"
|
||||
#include "document_wrappers.h"
|
||||
@ -25,6 +26,7 @@
|
||||
#include "gui/list.h"
|
||||
#include "modules/editors.h"
|
||||
#include "modules/gui.h"
|
||||
#include "raster/algorithm/flip_image.h"
|
||||
#include "raster/cel.h"
|
||||
#include "raster/image.h"
|
||||
#include "raster/mask.h"
|
||||
@ -100,6 +102,9 @@ void FlipCommand::onExecute(Context* context)
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
Mask* mask = NULL;
|
||||
bool alreadyFlipped = false;
|
||||
|
||||
// This variable will be the area to be flipped inside the image.
|
||||
gfx::Rect bounds(gfx::Point(0, 0),
|
||||
gfx::Size(image->w, image->h));
|
||||
@ -108,7 +113,7 @@ void FlipCommand::onExecute(Context* context)
|
||||
// selected region only. If the mask isn't visible, we flip the
|
||||
// whole image.
|
||||
if (document->isMaskVisible()) {
|
||||
Mask* mask = document->getMask();
|
||||
mask = document->getMask();
|
||||
gfx::Rect maskBounds = mask->getBounds();
|
||||
|
||||
// Adjust the mask depending on the cel position.
|
||||
@ -118,10 +123,39 @@ void FlipCommand::onExecute(Context* context)
|
||||
// bounds, so we don't request to flip an area outside the
|
||||
// image's bounds.
|
||||
bounds = bounds.createIntersect(maskBounds);
|
||||
|
||||
// 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(sprite->getCurrentLayer());
|
||||
|
||||
// Flip the portion of image specified by the mask.
|
||||
undoTransaction.flipImageWithMask(image, mask, m_flipType, bgcolor);
|
||||
alreadyFlipped = true;
|
||||
|
||||
// Flip the mask.
|
||||
Image* maskBitmap = mask->getBitmap();
|
||||
if (maskBitmap != NULL) {
|
||||
// Create a flipped copy of the current mask.
|
||||
UniquePtr<Mask> newMask(new Mask(*mask));
|
||||
newMask->freeze();
|
||||
raster::algorithm::flip_image(newMask->getBitmap(),
|
||||
gfx::Rect(gfx::Point(0, 0),
|
||||
gfx::Size(maskBitmap->w, maskBitmap->h)),
|
||||
m_flipType);
|
||||
newMask->unfreeze();
|
||||
|
||||
// Change the current mask and generate the new boundaries.
|
||||
undoTransaction.copyToCurrentMask(newMask);
|
||||
|
||||
document->generateMaskBoundaries();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flip the portion of image specified by "bounds" variable.
|
||||
undoTransaction.flipImage(image, bounds, m_flipType);
|
||||
if (!alreadyFlipped) {
|
||||
undoTransaction.flipImage(image, bounds, m_flipType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// get all sprite cels
|
||||
|
@ -20,12 +20,15 @@
|
||||
|
||||
#include "raster/algorithm/flip_image.h"
|
||||
|
||||
#include "base/unique_ptr.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "raster/image.h"
|
||||
#include "raster/mask.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace raster { namespace algorithm {
|
||||
namespace raster {
|
||||
namespace algorithm {
|
||||
|
||||
void flip_image(Image* image, const gfx::Rect& bounds, FlipType flipType)
|
||||
{
|
||||
@ -62,4 +65,52 @@ void flip_image(Image* image, const gfx::Rect& bounds, FlipType flipType)
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
void flip_image_with_mask(Image* image, const Mask* mask, FlipType flipType, int bgcolor)
|
||||
{
|
||||
gfx::Rect bounds = mask->getBounds();
|
||||
|
||||
switch (flipType) {
|
||||
|
||||
case FlipHorizontal: {
|
||||
UniquePtr<Image> originalRow(Image::create(image->getPixelFormat(), mask->getBounds().w, 1));
|
||||
|
||||
for (int y=bounds.y; y<bounds.y+bounds.h; ++y) {
|
||||
// Copy the current row.
|
||||
image_copy(originalRow, image, -bounds.x, -y);
|
||||
|
||||
int u = bounds.x+bounds.w-1;
|
||||
for (int x=bounds.x; x<bounds.x+bounds.w; ++x, --u) {
|
||||
if (mask->containsPoint(x, y)) {
|
||||
image_putpixel(image, u, y, image_getpixel(originalRow, x-bounds.x, 0));
|
||||
if (!mask->containsPoint(u, y))
|
||||
image_putpixel(image, x, y, bgcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipVertical:{
|
||||
UniquePtr<Image> originalCol(Image::create(image->getPixelFormat(), 1, mask->getBounds().h));
|
||||
|
||||
for (int x=bounds.x; x<bounds.x+bounds.w; ++x) {
|
||||
// Copy the current column.
|
||||
image_copy(originalCol, image, -x, -bounds.y);
|
||||
|
||||
int v = bounds.y+bounds.h-1;
|
||||
for (int y=bounds.y; y<bounds.y+bounds.h; ++y, --v) {
|
||||
if (mask->containsPoint(x, y)) {
|
||||
image_putpixel(image, x, v, image_getpixel(originalCol, 0, y-bounds.y));
|
||||
if (!mask->containsPoint(x, v))
|
||||
image_putpixel(image, x, y, bgcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
} // namespace raster
|
||||
|
@ -23,12 +23,19 @@
|
||||
#include "raster/algorithm/flip_type.h"
|
||||
|
||||
class Image;
|
||||
class Mask;
|
||||
|
||||
namespace raster {
|
||||
namespace algorithm {
|
||||
|
||||
// Flips the rectangular region specified in the "bounds" parameter.
|
||||
void flip_image(Image* image, const gfx::Rect& bounds, FlipType flipType);
|
||||
|
||||
// Flips an irregular region specified by the "mask". The
|
||||
// "bgcolor" is used to clear areas that aren't covered by a
|
||||
// mirrored pixel.
|
||||
void flip_image_with_mask(Image* image, const Mask* mask, FlipType flipType, int bgcolor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,26 @@ void Mask::unfreeze()
|
||||
shrink();
|
||||
}
|
||||
|
||||
bool Mask::isRectangular() const
|
||||
{
|
||||
if (!m_bitmap)
|
||||
return false;
|
||||
|
||||
for (int y=0; y<m_bitmap->h; ++y) {
|
||||
uint8_t* address = ((uint8_t**)m_bitmap->line)[y];
|
||||
div_t d = div(0, 8);
|
||||
|
||||
for (int x=0; x<m_bitmap->w; ++x) {
|
||||
if (((*address) & (1 << d.rem)) == 0)
|
||||
return false;
|
||||
|
||||
_image_bitmap_next_bit(d, address);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mask::copyFrom(const Mask* sourceMask)
|
||||
{
|
||||
clear();
|
||||
|
@ -74,6 +74,9 @@ public:
|
||||
// Returns true if the mask is frozen (See freeze/unfreeze functions).
|
||||
bool isFrozen() const { return m_freeze_count > 0; }
|
||||
|
||||
// Returns true if the mask is a rectangular region.
|
||||
bool isRectangular() const;
|
||||
|
||||
// Clears the mask.
|
||||
void clear();
|
||||
|
||||
|
@ -1065,6 +1065,25 @@ void UndoTransaction::flipImage(Image* image,
|
||||
raster::algorithm::flip_image(image, bounds, flipType);
|
||||
}
|
||||
|
||||
void UndoTransaction::flipImageWithMask(Image* image, const Mask* mask, raster::algorithm::FlipType flipType, int bgcolor)
|
||||
{
|
||||
UniquePtr<Image> flippedImage((Image::createCopy(image)));
|
||||
|
||||
// Flip the portion of the bitmap.
|
||||
raster::algorithm::flip_image_with_mask(flippedImage, mask, flipType, bgcolor);
|
||||
|
||||
// Insert the undo operation.
|
||||
if (isEnabled()) {
|
||||
UniquePtr<Dirty> dirty((new Dirty(image, flippedImage)));
|
||||
dirty->saveImagePixels(image);
|
||||
|
||||
m_undoHistory->pushUndoer(new undoers::DirtyArea(m_undoHistory->getObjects(), image, dirty));
|
||||
}
|
||||
|
||||
// Copy the flipped image into the image specified as argument.
|
||||
image_copy(image, flippedImage, 0, 0);
|
||||
}
|
||||
|
||||
void UndoTransaction::pasteImage(const Image* src_image, int x, int y, int opacity)
|
||||
{
|
||||
const Layer* layer = m_sprite->getCurrentLayer();
|
||||
|
@ -120,6 +120,7 @@ public:
|
||||
Image* getCelImage(Cel* cel);
|
||||
void clearMask(int bgcolor);
|
||||
void flipImage(Image* image, const gfx::Rect& bounds, raster::algorithm::FlipType flipType);
|
||||
void flipImageWithMask(Image* image, const Mask* mask, raster::algorithm::FlipType flipType, int bgcolor);
|
||||
void pasteImage(const Image* src_image, int x, int y, int opacity);
|
||||
|
||||
// for mask
|
||||
|
Loading…
x
Reference in New Issue
Block a user