mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-13 15:39:59 +00:00
Add 9-slice transformation support
This commit is contained in:
parent
ca75a98679
commit
fb74feea21
@ -21,7 +21,6 @@
|
|||||||
#include "app/ui/status_bar.h"
|
#include "app/ui/status_bar.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
#include "app/util/expand_cel_canvas.h"
|
#include "app/util/expand_cel_canvas.h"
|
||||||
#include "app/util/new_image_from_mask.h"
|
|
||||||
#include "doc/algorithm/rotate.h"
|
#include "doc/algorithm/rotate.h"
|
||||||
#include "doc/blend_internals.h"
|
#include "doc/blend_internals.h"
|
||||||
#include "doc/color.h"
|
#include "doc/color.h"
|
||||||
@ -90,66 +89,44 @@ MovingSliceState::MovingSliceState(Editor* editor,
|
|||||||
editor->captureMouse();
|
editor->captureMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MovingSliceState::initializeItemsContent() {
|
||||||
|
for (auto& item : m_items) {
|
||||||
|
// Align slice origin to tiles origin under Tiles mode.
|
||||||
|
if (m_site.tilemapMode() == TilemapMode::Tiles) {
|
||||||
|
auto origin = m_site.grid().tileToCanvas(m_site.grid().canvasToTile(item.newKey.bounds().origin()));
|
||||||
|
auto bounds = gfx::Rect(origin, item.newKey.bounds().size());
|
||||||
|
item.newKey.setBounds(bounds);
|
||||||
|
}
|
||||||
|
// Reserve one ItemContent slot for each selected layer.
|
||||||
|
item.content.reserve(m_selectedLayers.size());
|
||||||
|
|
||||||
|
for (const auto* layer : m_selectedLayers) {
|
||||||
|
Mask mask;
|
||||||
|
ImageRef image = ImageRef();
|
||||||
|
|
||||||
|
mask.add(item.newKey.bounds());
|
||||||
|
if (layer &&
|
||||||
|
layer->isTilemap() &&
|
||||||
|
m_site.tilemapMode() == TilemapMode::Tiles) {
|
||||||
|
image.reset(new_tilemap_from_mask(m_site, &mask));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
image.reset(new_image_from_mask(
|
||||||
|
*layer,
|
||||||
|
m_frame,
|
||||||
|
&mask,
|
||||||
|
Preferences::instance().experimental.newBlend()));
|
||||||
|
}
|
||||||
|
|
||||||
|
item.pushContent(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MovingSliceState::onEnterState(Editor* editor)
|
void MovingSliceState::onEnterState(Editor* editor)
|
||||||
{
|
{
|
||||||
if (editor->slicesTransforms() && !m_items.empty()) {
|
if (editor->slicesTransforms() && !m_items.empty()) {
|
||||||
for (auto& item : m_items) {
|
initializeItemsContent();
|
||||||
// Align slice origin to tiles origin under Tiles mode.
|
|
||||||
if (m_site.tilemapMode() == TilemapMode::Tiles) {
|
|
||||||
auto origin = m_site.grid().tileToCanvas(m_site.grid().canvasToTile(item.newKey.bounds().origin()));
|
|
||||||
auto bounds = gfx::Rect(origin, item.newKey.bounds().size());
|
|
||||||
item.newKey.setBounds(bounds);
|
|
||||||
}
|
|
||||||
item.imgs.reserve(m_selectedLayers.size());
|
|
||||||
item.masks.reserve(m_selectedLayers.size());
|
|
||||||
int i = 0;
|
|
||||||
for (const auto* layer : m_selectedLayers) {
|
|
||||||
item.masks.push_back(std::make_shared<Mask>());
|
|
||||||
item.imgs.push_back(ImageRef());
|
|
||||||
item.masks[i]->add(item.newKey.bounds());
|
|
||||||
item.masks[i]->freeze();
|
|
||||||
if (layer &&
|
|
||||||
layer->isTilemap() &&
|
|
||||||
m_site.tilemapMode() == TilemapMode::Tiles) {
|
|
||||||
item.imgs[i].reset(new_tilemap_from_mask(m_site, item.masks[i].get()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item.imgs[i].reset(new_image_from_mask(
|
|
||||||
*layer,
|
|
||||||
m_frame,
|
|
||||||
item.masks[i].get(),
|
|
||||||
Preferences::instance().experimental.newBlend()));
|
|
||||||
// TODO: See if part of the code in fromImage can be replaced
|
|
||||||
// refactored to use mask_image (in cel_ops.h)?
|
|
||||||
item.masks[i]->fromImage(item.imgs[i].get(), item.masks[i]->origin());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is just one layer selected, we can use the same image as the
|
|
||||||
// mergedImg.
|
|
||||||
if (m_selectedLayers.size() == 1) {
|
|
||||||
item.mergedImg = item.imgs[0];
|
|
||||||
item.mergedMask = item.masks[0];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (i == 0) {
|
|
||||||
const gfx::Rect& srcBounds = item.imgs[i]->bounds();
|
|
||||||
item.mergedImg.reset(Image::create(layer->sprite()->pixelFormat(), srcBounds.w, srcBounds.h));
|
|
||||||
item.mergedImg->clear(layer->sprite()->transparentColor());
|
|
||||||
item.mergedMask = std::make_shared<Mask>(*item.masks[i].get());
|
|
||||||
item.mergedMask->freeze();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item.mergedMask->add(*item.masks[i].get());
|
|
||||||
}
|
|
||||||
copy_masked_zones(item.mergedImg.get(),
|
|
||||||
item.imgs[i].get(),
|
|
||||||
item.masks[i].get(),
|
|
||||||
item.masks[i]->bounds().x,
|
|
||||||
item.masks[i]->bounds().y);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear brush preview, as the extra cel will be replaced with the
|
// Clear brush preview, as the extra cel will be replaced with the
|
||||||
// transformed image.
|
// transformed image.
|
||||||
@ -157,7 +134,7 @@ void MovingSliceState::onEnterState(Editor* editor)
|
|||||||
|
|
||||||
clearSlices();
|
clearSlices();
|
||||||
|
|
||||||
drawSliceContents();
|
drawExtraCel();
|
||||||
|
|
||||||
// Redraw the editor.
|
// Redraw the editor.
|
||||||
editor->invalidate();
|
editor->invalidate();
|
||||||
@ -179,9 +156,10 @@ bool MovingSliceState::onMouseUp(Editor* editor, MouseMessage* msg)
|
|||||||
auto* layer = m_selectedLayers[i];
|
auto* layer = m_selectedLayers[i];
|
||||||
m_site.layer(layer);
|
m_site.layer(layer);
|
||||||
m_site.frame(m_frame);
|
m_site.frame(m_frame);
|
||||||
drawSliceContentsByLayer(i);
|
drawExtraCel(i);
|
||||||
stampExtraCelImage();
|
stampExtraCelImage();
|
||||||
}
|
}
|
||||||
|
m_site.document()->setExtraCel(ExtraCelRef(nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,41 +204,7 @@ void MovingSliceState::stampExtraCelImage()
|
|||||||
expand.commit();
|
expand.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MovingSliceState::drawSliceContents()
|
void MovingSliceState::drawExtraCel(int layerIdx)
|
||||||
{
|
|
||||||
gfx::Rect bounds;
|
|
||||||
for (auto& item : m_items)
|
|
||||||
bounds |= item.newKey.bounds();
|
|
||||||
|
|
||||||
drawExtraCel(bounds, [this](const gfx::Rect& bounds, Image* dst){
|
|
||||||
for (auto& item : m_items) {
|
|
||||||
// Draw the transformed pixels in the extra-cel which is the chunk
|
|
||||||
// of pixels that the user is moving.
|
|
||||||
drawImage(dst,
|
|
||||||
item.mergedImg.get(),
|
|
||||||
item.mergedMask.get(),
|
|
||||||
gfx::Rect(item.newKey.bounds()).offset(-bounds.origin()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovingSliceState::drawSliceContentsByLayer(int layerIdx)
|
|
||||||
{
|
|
||||||
gfx::Rect bounds;
|
|
||||||
for (auto& item : m_items)
|
|
||||||
bounds |= item.newKey.bounds();
|
|
||||||
|
|
||||||
drawExtraCel(bounds, [this, layerIdx](const gfx::Rect& bounds, Image* dst){
|
|
||||||
for (auto& item : m_items) {
|
|
||||||
drawImage(dst,
|
|
||||||
item.imgs[layerIdx].get(),
|
|
||||||
item.masks[layerIdx].get(),
|
|
||||||
gfx::Rect(item.newKey.bounds()).offset(-bounds.origin()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovingSliceState::drawExtraCel(const gfx::Rect& bounds, DrawExtraCelContentFunc drawContent)
|
|
||||||
{
|
{
|
||||||
int t, opacity = (m_site.layer()->isImage() ?
|
int t, opacity = (m_site.layer()->isImage() ?
|
||||||
static_cast<LayerImage*>(m_site.layer())->opacity(): 255);
|
static_cast<LayerImage*>(m_site.layer())->opacity(): 255);
|
||||||
@ -270,6 +214,10 @@ void MovingSliceState::drawExtraCel(const gfx::Rect& bounds, DrawExtraCelContent
|
|||||||
if (!m_extraCel)
|
if (!m_extraCel)
|
||||||
m_extraCel.reset(new ExtraCel);
|
m_extraCel.reset(new ExtraCel);
|
||||||
|
|
||||||
|
gfx::Rect bounds;
|
||||||
|
for (auto& item : m_items)
|
||||||
|
bounds |= item.newKey.bounds();
|
||||||
|
|
||||||
if (!bounds.isEmpty()) {
|
if (!bounds.isEmpty()) {
|
||||||
gfx::Size extraCelSize;
|
gfx::Size extraCelSize;
|
||||||
if (m_site.tilemapMode() == TilemapMode::Tiles) {
|
if (m_site.tilemapMode() == TilemapMode::Tiles) {
|
||||||
@ -319,13 +267,31 @@ void MovingSliceState::drawExtraCel(const gfx::Rect& bounds, DrawExtraCelContent
|
|||||||
dst, m_site.layer(), m_site.frame(),
|
dst, m_site.layer(), m_site.frame(),
|
||||||
gfx::Clip(0, 0, bounds),
|
gfx::Clip(0, 0, bounds),
|
||||||
doc::BlendMode::SRC);
|
doc::BlendMode::SRC);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawContent(bounds, dst);
|
for (auto& item : m_items) {
|
||||||
|
// Draw the transformed pixels in the extra-cel which is the chunk
|
||||||
|
// of pixels that the user is moving.
|
||||||
|
drawItem(dst, item, bounds.origin(), layerIdx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MovingSliceState::drawItem(doc::Image* dst,
|
||||||
|
const Item& item,
|
||||||
|
const gfx::Point& itemsBoundsOrigin,
|
||||||
|
int layerIdx)
|
||||||
|
{
|
||||||
|
const ItemContentRef content = (layerIdx >= 0 ? item.content[layerIdx]
|
||||||
|
: item.mergedContent);
|
||||||
|
|
||||||
|
content->forEachPart(
|
||||||
|
[this, dst, itemsBoundsOrigin]
|
||||||
|
(const doc::Image* src, const doc::Mask* mask, const gfx::Rect& bounds) {
|
||||||
|
drawImage(dst, src, mask, gfx::Rect(bounds).offset(-itemsBoundsOrigin));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void MovingSliceState::drawImage(doc::Image* dst,
|
void MovingSliceState::drawImage(doc::Image* dst,
|
||||||
const doc::Image* src,
|
const doc::Image* src,
|
||||||
const doc::Mask* mask,
|
const doc::Mask* mask,
|
||||||
@ -347,7 +313,7 @@ void MovingSliceState::drawImage(doc::Image* dst,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
doc::algorithm::parallelogram(
|
doc::algorithm::parallelogram(
|
||||||
dst, src, mask->bitmap(),
|
dst, src, (mask ? mask->bitmap() : nullptr),
|
||||||
bounds.x , bounds.y,
|
bounds.x , bounds.y,
|
||||||
bounds.x+bounds.w, bounds.y,
|
bounds.x+bounds.w, bounds.y,
|
||||||
bounds.x+bounds.w, bounds.y+bounds.h,
|
bounds.x+bounds.w, bounds.y+bounds.h,
|
||||||
@ -459,7 +425,7 @@ bool MovingSliceState::onMouseMove(Editor* editor, MouseMessage* msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (editor->slicesTransforms())
|
if (editor->slicesTransforms())
|
||||||
drawSliceContents();
|
drawExtraCel();
|
||||||
|
|
||||||
// Redraw the editor.
|
// Redraw the editor.
|
||||||
editor->invalidate();
|
editor->invalidate();
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "app/ui/editor/editor_hit.h"
|
#include "app/ui/editor/editor_hit.h"
|
||||||
#include "app/ui/editor/standby_state.h"
|
#include "app/ui/editor/standby_state.h"
|
||||||
#include "app/ui/editor/pixels_movement.h"
|
#include "app/ui/editor/pixels_movement.h"
|
||||||
|
#include "app/util/new_image_from_mask.h"
|
||||||
#include "doc/frame.h"
|
#include "doc/frame.h"
|
||||||
#include "doc/image_ref.h"
|
#include "doc/image_ref.h"
|
||||||
#include "doc/mask.h"
|
#include "doc/mask.h"
|
||||||
@ -37,38 +38,167 @@ namespace app {
|
|||||||
bool requireBrushPreview() override { return false; }
|
bool requireBrushPreview() override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using DrawExtraCelContentFunc = std::function<void(const gfx::Rect& bounds, Image* dst)>;
|
struct Item;
|
||||||
|
using ItemContentPartFunc = std::function<
|
||||||
|
void(const doc::Image* src,
|
||||||
|
const doc::Mask* mask,
|
||||||
|
const gfx::Rect& bounds)>;
|
||||||
|
|
||||||
|
class ItemContent {
|
||||||
|
public:
|
||||||
|
ItemContent(const Item *item) : m_item(item) {}
|
||||||
|
virtual ~ItemContent() {};
|
||||||
|
virtual void forEachPart(ItemContentPartFunc fn) = 0;
|
||||||
|
virtual void copy(const Image* src) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Item* m_item = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ItemContentRef = std::shared_ptr<ItemContent>;
|
||||||
|
|
||||||
|
class SingleSlice : public ItemContent {
|
||||||
|
public:
|
||||||
|
SingleSlice(const Item *item,
|
||||||
|
const ImageRef& image) : SingleSlice(item, image, item->oldKey.bounds().origin()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleSlice(const Item *item,
|
||||||
|
const ImageRef& image,
|
||||||
|
const gfx::Point& origin) : ItemContent(item)
|
||||||
|
, m_img(image) {
|
||||||
|
m_mask = std::make_shared<Mask>();
|
||||||
|
m_mask->freeze();
|
||||||
|
m_mask->fromImage(m_img.get(), origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SingleSlice() {
|
||||||
|
m_mask->unfreeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEachPart(ItemContentPartFunc fn) override {
|
||||||
|
fn(m_img.get(), m_mask.get(), m_item->newKey.bounds());
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy(const Image* src) override {
|
||||||
|
doc::Mask srcMask;
|
||||||
|
srcMask.freeze();
|
||||||
|
srcMask.add(m_item->oldKey.bounds());
|
||||||
|
// TODO: See if part of the code in fromImage can be replaced or
|
||||||
|
// refactored to use mask_image (in cel_ops.h)?
|
||||||
|
srcMask.fromImage(src, srcMask.origin());
|
||||||
|
copy_masked_zones(m_img.get(), src, &srcMask, srcMask.bounds().x, srcMask.bounds().y);
|
||||||
|
|
||||||
|
m_mask->add(srcMask);
|
||||||
|
srcMask.unfreeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Image* image() { return m_img.get(); }
|
||||||
|
Mask* mask() { return m_mask.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Images containing the parts of each selected layer of the sprite under
|
||||||
|
// the slice bounds that will be transformed when Slice Transform is
|
||||||
|
// enabled
|
||||||
|
ImageRef m_img;
|
||||||
|
// Masks for each of the images in imgs vector
|
||||||
|
MaskRef m_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NineSlice : public ItemContent {
|
||||||
|
public:
|
||||||
|
NineSlice(const Item *item,
|
||||||
|
const ImageRef& image) : ItemContent(item) {
|
||||||
|
|
||||||
|
if (!m_item->oldKey.hasCenter()) return;
|
||||||
|
|
||||||
|
const gfx::Rect totalBounds(m_item->oldKey.bounds().size());
|
||||||
|
gfx::Rect bounds[9];
|
||||||
|
totalBounds.nineSlice(m_item->oldKey.center(), bounds);
|
||||||
|
for (int i=0; i<9; ++i) {
|
||||||
|
if (!bounds[i].isEmpty()) {
|
||||||
|
ImageRef img;
|
||||||
|
img.reset(Image::create(image->pixelFormat(), bounds[i].w, bounds[i].h));
|
||||||
|
img->copy(image.get(), gfx::Clip(0, 0, bounds[i]));
|
||||||
|
m_part[i] = std::make_unique<SingleSlice>(m_item, img, bounds[i].origin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~NineSlice() {}
|
||||||
|
|
||||||
|
void forEachPart(ItemContentPartFunc fn) override {
|
||||||
|
gfx::Rect bounds[9];
|
||||||
|
m_item->newKey.bounds().nineSlice(m_item->newKey.center(), bounds);
|
||||||
|
for (int i=0; i<9; ++i) {
|
||||||
|
if (m_part[i])
|
||||||
|
fn(m_part[i]->image(), m_part[i]->mask(), bounds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy(const Image* src) override {
|
||||||
|
if (!m_item->oldKey.hasCenter()) return;
|
||||||
|
|
||||||
|
const gfx::Rect totalBounds(m_item->oldKey.bounds().size());
|
||||||
|
gfx::Rect bounds[9];
|
||||||
|
totalBounds.nineSlice(m_item->oldKey.center(), bounds);
|
||||||
|
for (int i=0; i<9; ++i) {
|
||||||
|
if (!bounds[i].isEmpty()) {
|
||||||
|
ImageRef img;
|
||||||
|
img.reset(Image::create(src->pixelFormat(), bounds[i].w, bounds[i].h));
|
||||||
|
img->copy(src, gfx::Clip(0, 0, bounds[i]));
|
||||||
|
m_part[i]->copy(img.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<SingleSlice> m_part[9] = {nullptr, nullptr, nullptr,
|
||||||
|
nullptr, nullptr, nullptr,
|
||||||
|
nullptr, nullptr, nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Item {
|
struct Item {
|
||||||
doc::Slice* slice;
|
doc::Slice* slice;
|
||||||
doc::SliceKey oldKey;
|
doc::SliceKey oldKey;
|
||||||
doc::SliceKey newKey;
|
doc::SliceKey newKey;
|
||||||
// Images containing the parts of each selected layer of the sprite under
|
// Vector of each selected layer's part of the sprite under
|
||||||
// the slice bounds that will be transformed when Slice Transform is
|
// the slice bounds that will be transformed when Slice Transform is
|
||||||
// enabled
|
// enabled
|
||||||
std::vector<ImageRef> imgs;
|
std::vector<ItemContentRef> content;
|
||||||
// Masks for each of the images in imgs vector
|
ItemContentRef mergedContent;
|
||||||
std::vector<MaskRef> masks;
|
|
||||||
|
|
||||||
// Image containing the result of merging all the images in the imgs
|
void pushContent(const ImageRef& image) {
|
||||||
// vector
|
if (content.empty()) {
|
||||||
ImageRef mergedImg = nullptr;
|
const gfx::Rect& srcBounds = image->bounds();
|
||||||
MaskRef mergedMask = nullptr;
|
ImageRef mergedImage;
|
||||||
|
mergedImage.reset(Image::create(image->pixelFormat(), srcBounds.w, srcBounds.h));
|
||||||
|
mergedImage->clear(image->maskColor());
|
||||||
|
mergedContent = (this->oldKey.hasCenter() ? (ItemContentRef)std::make_shared<NineSlice>(this, mergedImage)
|
||||||
|
: std::make_shared<SingleSlice>(this, mergedImage));
|
||||||
|
}
|
||||||
|
|
||||||
~Item() {
|
mergedContent->copy(image.get());
|
||||||
if (!masks.empty() && mergedMask != masks[0])
|
|
||||||
mergedMask->unfreeze();
|
ItemContentRef ssc = (this->oldKey.hasCenter() ? (ItemContentRef)std::make_shared<NineSlice>(this, image)
|
||||||
for (auto& m : masks)
|
: std::make_shared<SingleSlice>(this, image));
|
||||||
m->unfreeze();
|
content.push_back(ssc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Initializes the content of the Items. So each item will contain the
|
||||||
|
// part of the cel's layers within the corresponding slice.
|
||||||
|
void initializeItemsContent();
|
||||||
|
|
||||||
Item getItemForSlice(doc::Slice* slice);
|
Item getItemForSlice(doc::Slice* slice);
|
||||||
gfx::Rect selectedSlicesBounds() const;
|
gfx::Rect selectedSlicesBounds() const;
|
||||||
|
|
||||||
void drawSliceContents();
|
void drawExtraCel(int layerIdx = -1);
|
||||||
void drawSliceContentsByLayer(int layerIdx);
|
void drawItem(doc::Image* dst,
|
||||||
void drawExtraCel(const gfx::Rect& bounds, DrawExtraCelContentFunc drawContent);
|
const Item& item,
|
||||||
|
const gfx::Point& itemsBoundsOrigin,
|
||||||
|
int layerIdx);
|
||||||
void drawImage(doc::Image* dst,
|
void drawImage(doc::Image* dst,
|
||||||
const doc::Image* src,
|
const doc::Image* src,
|
||||||
const doc::Mask* mask,
|
const doc::Mask* mask,
|
||||||
|
@ -127,13 +127,16 @@ doc::Image* new_image_from_mask(const Layer& layer,
|
|||||||
src = dst.get();
|
src = dst.get();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
src = cel->image();
|
if (cel) {
|
||||||
x = cel->x();
|
src = cel->image();
|
||||||
y = cel->y();
|
x = cel->x();
|
||||||
|
y = cel->y();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the masked zones
|
if (src)
|
||||||
copy_masked_zones(dst.get(), src, srcMask, x, y);
|
// Copy the masked zones
|
||||||
|
copy_masked_zones(dst.get(), src, srcMask, x, y);
|
||||||
|
|
||||||
return dst.release();
|
return dst.release();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user