mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-09 18:44:46 +00:00
138 lines
3.6 KiB
C++
138 lines
3.6 KiB
C++
// Aseprite
|
|
// Copyright (C) 2018 David Capello
|
|
//
|
|
// This program is distributed under the terms of
|
|
// the End-User License Agreement for Aseprite.
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "app/util/layer_boundaries.h"
|
|
|
|
#include "app/cmd/set_mask.h"
|
|
#include "app/console.h"
|
|
#include "app/context_access.h"
|
|
#include "app/modules/gui.h"
|
|
#include "app/transaction.h"
|
|
#include "app/ui_context.h"
|
|
#include "doc/cel.h"
|
|
#include "doc/document.h"
|
|
#include "doc/image.h"
|
|
#include "doc/image_impl.h"
|
|
#include "doc/layer.h"
|
|
#include "doc/mask.h"
|
|
|
|
using namespace doc;
|
|
|
|
namespace app {
|
|
|
|
void select_layer_boundaries(Layer* layer,
|
|
const frame_t frame,
|
|
const SelectLayerBoundariesOp op)
|
|
{
|
|
Mask newMask;
|
|
|
|
const Cel* cel = layer->cel(frame);
|
|
if (cel) {
|
|
const Image* image = cel->image();
|
|
if (image) {
|
|
newMask.replace(cel->bounds());
|
|
newMask.freeze();
|
|
{
|
|
LockImageBits<BitmapTraits> maskBits(newMask.bitmap());
|
|
auto maskIt = maskBits.begin();
|
|
auto maskEnd = maskBits.end();
|
|
|
|
switch (image->pixelFormat()) {
|
|
|
|
case IMAGE_RGB: {
|
|
LockImageBits<RgbTraits> rgbBits(image);
|
|
auto rgbIt = rgbBits.begin();
|
|
#if _DEBUG
|
|
auto rgbEnd = rgbBits.end();
|
|
#endif
|
|
for (; maskIt != maskEnd; ++maskIt, ++rgbIt) {
|
|
ASSERT(rgbIt != rgbEnd);
|
|
color_t c = *rgbIt;
|
|
*maskIt = (rgba_geta(c) >= 128); // TODO configurable threshold
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IMAGE_GRAYSCALE: {
|
|
LockImageBits<GrayscaleTraits> grayBits(image);
|
|
auto grayIt = grayBits.begin();
|
|
#if _DEBUG
|
|
auto grayEnd = grayBits.end();
|
|
#endif
|
|
for (; maskIt != maskEnd; ++maskIt, ++grayIt) {
|
|
ASSERT(grayIt != grayEnd);
|
|
color_t c = *grayIt;
|
|
*maskIt = (graya_geta(c) >= 128); // TODO configurable threshold
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IMAGE_INDEXED: {
|
|
const doc::color_t maskColor = image->maskColor();
|
|
LockImageBits<IndexedTraits> idxBits(image);
|
|
auto idxIt = idxBits.begin();
|
|
#if _DEBUG
|
|
auto idxEnd = idxBits.end();
|
|
#endif
|
|
for (; maskIt != maskEnd; ++maskIt, ++idxIt) {
|
|
ASSERT(idxIt != idxEnd);
|
|
color_t c = *idxIt;
|
|
*maskIt = (c != maskColor);
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
newMask.unfreeze();
|
|
}
|
|
}
|
|
|
|
try {
|
|
ContextWriter writer(UIContext::instance(), 500);
|
|
app::Document* doc = writer.document();
|
|
Sprite* spr = layer->sprite();
|
|
ASSERT(doc == spr->document());
|
|
|
|
if (doc->isMaskVisible()) {
|
|
switch (op) {
|
|
case SelectLayerBoundariesOp::REPLACE:
|
|
// newMask is the new mask
|
|
break;
|
|
case SelectLayerBoundariesOp::ADD:
|
|
newMask.add(*doc->mask());
|
|
break;
|
|
case SelectLayerBoundariesOp::SUBTRACT: {
|
|
Mask oldMask(*doc->mask());
|
|
oldMask.subtract(newMask);
|
|
newMask.copyFrom(&oldMask); // TODO use something like std::swap()
|
|
break;
|
|
}
|
|
case SelectLayerBoundariesOp::INTERSECT:
|
|
newMask.intersect(*doc->mask());
|
|
break;
|
|
}
|
|
}
|
|
|
|
Transaction transaction(writer.context(), "Select Layer Boundaries", DoesntModifyDocument);
|
|
transaction.execute(new cmd::SetMask(doc, &newMask));
|
|
transaction.commit();
|
|
|
|
doc->resetTransformation();
|
|
doc->generateMaskBoundaries();
|
|
update_screen_for_document(doc);
|
|
}
|
|
catch (base::Exception& e) {
|
|
Console::showException(e);
|
|
}
|
|
}
|
|
|
|
} // namespace app
|