mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 04:19:12 +00:00
Added is_empty, freeze, unfreeze, add, reserve, and shrink function member of Mask class.
This commit is contained in:
parent
6e93dfe4ea
commit
33f804213d
@ -46,13 +46,13 @@ DeselectMaskCommand::DeselectMaskCommand()
|
||||
{
|
||||
}
|
||||
|
||||
bool DeselectMaskCommand::enabled(Context* context)
|
||||
{
|
||||
const CurrentSpriteReader sprite(context);
|
||||
return sprite && !mask_is_empty(sprite->mask);
|
||||
}
|
||||
|
||||
void DeselectMaskCommand::execute(Context* context)
|
||||
bool DeselectMaskCommand::enabled(Context* context)
|
||||
{
|
||||
const CurrentSpriteReader sprite(context);
|
||||
return sprite && !sprite->mask->is_empty();
|
||||
}
|
||||
|
||||
void DeselectMaskCommand::execute(Context* context)
|
||||
{
|
||||
CurrentSpriteWriter sprite(context);
|
||||
Mask *mask;
|
||||
|
@ -100,13 +100,13 @@ void FlipCommand::execute(Context* context)
|
||||
|
||||
image = GetImage2(sprite, &x, &y, NULL);
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
// mask is empty?
|
||||
if (mask_is_empty(sprite->mask)) {
|
||||
// so we flip the entire image
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
return;
|
||||
|
||||
// mask is empty?
|
||||
if (sprite->mask->is_empty()) {
|
||||
// so we flip the entire image
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
x2 = image->w-1;
|
||||
y2 = image->h-1;
|
||||
}
|
||||
|
@ -25,8 +25,6 @@
|
||||
#include "raster/image.h"
|
||||
#include "raster/mask.h"
|
||||
|
||||
static void shrink_mask(Mask* mask);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
Mask::Mask()
|
||||
@ -44,6 +42,8 @@ Mask::Mask(const Mask& mask)
|
||||
|
||||
Mask::~Mask()
|
||||
{
|
||||
assert(m_freeze_count == 0);
|
||||
|
||||
if (this->name)
|
||||
jfree(this->name);
|
||||
|
||||
@ -53,6 +53,7 @@ Mask::~Mask()
|
||||
|
||||
void Mask::initialize()
|
||||
{
|
||||
this->m_freeze_count = 0;
|
||||
this->name = NULL;
|
||||
this->x = 0;
|
||||
this->y = 0;
|
||||
@ -61,6 +62,22 @@ void Mask::initialize()
|
||||
this->bitmap = NULL;
|
||||
}
|
||||
|
||||
void Mask::freeze()
|
||||
{
|
||||
assert(m_freeze_count >= 0);
|
||||
m_freeze_count++;
|
||||
}
|
||||
|
||||
void Mask::unfreeze()
|
||||
{
|
||||
assert(m_freeze_count > 0);
|
||||
m_freeze_count--;
|
||||
|
||||
// Shrink just in case
|
||||
if (m_freeze_count == 0)
|
||||
shrink();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
Mask* mask_new()
|
||||
@ -80,11 +97,6 @@ void mask_free(Mask* mask)
|
||||
delete mask;
|
||||
}
|
||||
|
||||
int mask_is_empty(Mask* mask)
|
||||
{
|
||||
return (!mask->bitmap)? TRUE: FALSE;
|
||||
}
|
||||
|
||||
void mask_set_name(Mask* mask, const char *name)
|
||||
{
|
||||
if (mask->name)
|
||||
@ -101,9 +113,9 @@ void mask_copy(Mask* mask_dst, const Mask* mask_src)
|
||||
mask_set_name(mask_dst, mask_src->name);
|
||||
|
||||
if (mask_src->bitmap) {
|
||||
/* add all the area of "mask" */
|
||||
mask_union(mask_dst, mask_src->x, mask_src->y,
|
||||
mask_src->w, mask_src->h);
|
||||
// add all the area of "mask"
|
||||
mask_dst->add(mask_src->x, mask_src->y,
|
||||
mask_src->w, mask_src->h);
|
||||
|
||||
/* and copy the "mask" bitmap */
|
||||
image_copy(mask_dst->bitmap, mask_src->bitmap, 0, 0);
|
||||
@ -140,11 +152,11 @@ void mask_invert(Mask* mask)
|
||||
address = ((ase_uint8 **)mask->bitmap->line)[v];
|
||||
for (u=0; u<mask->w; u++) {
|
||||
*address ^= (1<<d.rem);
|
||||
_image_bitmap_next_bit (d, address);
|
||||
_image_bitmap_next_bit(d, address);
|
||||
}
|
||||
}
|
||||
|
||||
shrink_mask (mask);
|
||||
mask->shrink();
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,33 +176,17 @@ void mask_replace(Mask* mask, int x, int y, int w, int h)
|
||||
|
||||
void mask_union(Mask* mask, int x, int y, int w, int h)
|
||||
{
|
||||
if (!mask->bitmap) {
|
||||
mask->x = x;
|
||||
mask->y = y;
|
||||
mask->w = w;
|
||||
mask->h = h;
|
||||
mask->bitmap = image_new(IMAGE_BITMAP, w, h);
|
||||
}
|
||||
else {
|
||||
Image *image;
|
||||
int x1 = mask->x;
|
||||
int y1 = mask->y;
|
||||
int x2 = MAX(mask->x+mask->w-1, x+w-1);
|
||||
int y2 = MAX(mask->y+mask->h-1, y+h-1);
|
||||
mask->add(x, y, w, h);
|
||||
}
|
||||
|
||||
mask->x = MIN(x, x1);
|
||||
mask->y = MIN(y, y1);
|
||||
mask->w = x2 - mask->x + 1;
|
||||
mask->h = y2 - mask->y + 1;
|
||||
void Mask::add(int x, int y, int w, int h)
|
||||
{
|
||||
if (m_freeze_count == 0)
|
||||
this->reserve(x, y, w, h);
|
||||
|
||||
image = image_crop(mask->bitmap, mask->x-x1, mask->y-y1, mask->w, mask->h, 0);
|
||||
image_free(mask->bitmap);
|
||||
mask->bitmap = image;
|
||||
}
|
||||
|
||||
image_rectfill(mask->bitmap,
|
||||
x-mask->x, y-mask->y,
|
||||
x-mask->x+w-1, y-mask->y+h-1, 1);
|
||||
image_rectfill(this->bitmap,
|
||||
x-this->x, y-this->y,
|
||||
x-this->x+w-1, y-this->y+h-1, 1);
|
||||
}
|
||||
|
||||
void mask_subtract(Mask* mask, int x, int y, int w, int h)
|
||||
@ -199,7 +195,7 @@ void mask_subtract(Mask* mask, int x, int y, int w, int h)
|
||||
image_rectfill(mask->bitmap,
|
||||
x-mask->x, y-mask->y,
|
||||
x-mask->x+w-1, y-mask->y+h-1, 0);
|
||||
shrink_mask(mask);
|
||||
mask->shrink();
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,16 +217,10 @@ void mask_intersect(Mask* mask, int x, int y, int w, int h)
|
||||
image_free(mask->bitmap);
|
||||
mask->bitmap = image;
|
||||
|
||||
shrink_mask(mask);
|
||||
mask->shrink();
|
||||
}
|
||||
}
|
||||
|
||||
void mask_merge(Mask* mask, const Mask* src)
|
||||
{
|
||||
/* TODO!!! */
|
||||
assert(FALSE);
|
||||
}
|
||||
|
||||
void mask_by_color(Mask* mask, const Image *src, int color, int fuzziness)
|
||||
{
|
||||
Image *dst;
|
||||
@ -335,30 +325,9 @@ void mask_by_color(Mask* mask, const Image *src, int color, int fuzziness)
|
||||
} break;
|
||||
}
|
||||
|
||||
shrink_mask(mask);
|
||||
mask->shrink();
|
||||
}
|
||||
|
||||
/* void mask_fill (Mask* mask, Image *image, int color) */
|
||||
/* { */
|
||||
/* if (mask) { */
|
||||
/* ase_uint8 *address; */
|
||||
/* int u, v; */
|
||||
/* div_t d; */
|
||||
|
||||
/* for (v=0; v<h; v++) { */
|
||||
/* d = div (0, 8); */
|
||||
/* address = ((ase_uint8 **)drawable->lines)[v]+d.quot; */
|
||||
|
||||
/* for (u=0; u<w; u++) { */
|
||||
/* if ((*address) & (1<<d.rem)) */
|
||||
/* drawable->putpixel (x+u, y+v, color); */
|
||||
|
||||
/* _drawable_bitmap_next_bit (d, address); */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } */
|
||||
|
||||
void mask_crop(Mask* mask, const Image *image)
|
||||
{
|
||||
#define ADVANCE(beg, end, o_end, cmp, op, getpixel1, getpixel) \
|
||||
@ -393,44 +362,86 @@ void mask_crop(Mask* mask, const Image *image)
|
||||
beg_x2 = beg_x1 + mask->w - 1;
|
||||
beg_y2 = beg_y1 + mask->h - 1;
|
||||
|
||||
beg_x1 = MID (0, beg_x1, mask->w-1);
|
||||
beg_y1 = MID (0, beg_y1, mask->h-1);
|
||||
beg_x2 = MID (beg_x1, beg_x2, mask->w-1);
|
||||
beg_y2 = MID (beg_y1, beg_y2, mask->h-1);
|
||||
beg_x1 = MID(0, beg_x1, mask->w-1);
|
||||
beg_y1 = MID(0, beg_y1, mask->h-1);
|
||||
beg_x2 = MID(beg_x1, beg_x2, mask->w-1);
|
||||
beg_y2 = MID(beg_y1, beg_y2, mask->h-1);
|
||||
|
||||
/* left */
|
||||
ADVANCE (x1, x2, y2, <=, ++,
|
||||
image_getpixel (image, x1, c=beg_y1),
|
||||
image_getpixel (image, x1, c));
|
||||
ADVANCE(x1, x2, y2, <=, ++,
|
||||
image_getpixel(image, x1, c=beg_y1),
|
||||
image_getpixel(image, x1, c));
|
||||
/* right */
|
||||
ADVANCE (x2, x1, y2, >=, --,
|
||||
image_getpixel (image, x2, c=beg_y1),
|
||||
image_getpixel (image, x2, c));
|
||||
ADVANCE(x2, x1, y2, >=, --,
|
||||
image_getpixel(image, x2, c=beg_y1),
|
||||
image_getpixel(image, x2, c));
|
||||
/* top */
|
||||
ADVANCE (y1, y2, x2, <=, ++,
|
||||
image_getpixel (image, c=beg_x1, y1),
|
||||
image_getpixel (image, c, y1));
|
||||
ADVANCE(y1, y2, x2, <=, ++,
|
||||
image_getpixel(image, c=beg_x1, y1),
|
||||
image_getpixel(image, c, y1));
|
||||
/* bottom */
|
||||
ADVANCE (y2, y1, x2, >=, --,
|
||||
image_getpixel (image, c=beg_x1, y2),
|
||||
image_getpixel (image, c, y2));
|
||||
ADVANCE(y2, y1, x2, >=, --,
|
||||
image_getpixel(image, c=beg_x1, y2),
|
||||
image_getpixel(image, c, y2));
|
||||
|
||||
if (done_count < 4)
|
||||
mask_intersect (mask, x1, y1, x2, y2);
|
||||
mask_intersect(mask, x1, y1, x2, y2);
|
||||
else
|
||||
mask_none (mask);
|
||||
mask_none(mask);
|
||||
|
||||
#undef ADVANCE
|
||||
}
|
||||
|
||||
static void shrink_mask(Mask* mask)
|
||||
void Mask::reserve(int x, int y, int w, int h)
|
||||
{
|
||||
assert(w > 0 && h > 0);
|
||||
|
||||
if (!this->bitmap) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
this->bitmap = image_new(IMAGE_BITMAP, w, h);
|
||||
image_clear(this->bitmap, 0);
|
||||
}
|
||||
else {
|
||||
int x1 = this->x;
|
||||
int y1 = this->y;
|
||||
int x2 = MAX(this->x+this->w-1, x+w-1);
|
||||
int y2 = MAX(this->y+this->h-1, y+h-1);
|
||||
int new_mask_x = MIN(x, x1);
|
||||
int new_mask_y = MIN(y, y1);
|
||||
int new_mask_w = x2 - new_mask_x + 1;
|
||||
int new_mask_h = y2 - new_mask_y + 1;
|
||||
|
||||
if (this->x != new_mask_x ||
|
||||
this->y != new_mask_y ||
|
||||
this->w != new_mask_w ||
|
||||
this->h != new_mask_h) {
|
||||
this->x = new_mask_x;
|
||||
this->y = new_mask_y;
|
||||
this->w = new_mask_w;
|
||||
this->h = new_mask_h;
|
||||
|
||||
Image* image = image_crop(this->bitmap, this->x-x1, this->y-y1, this->w, this->h, 0);
|
||||
delete this->bitmap; // image
|
||||
this->bitmap = image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mask::shrink()
|
||||
{
|
||||
// If the mask is frozen we avoid the shrinking
|
||||
if (m_freeze_count > 0)
|
||||
return;
|
||||
|
||||
#define SHRINK_SIDE(u_begin, u_op, u_final, u_add, \
|
||||
v_begin, v_op, v_final, v_add, U, V, var) \
|
||||
{ \
|
||||
for (u = u_begin; u u_op u_final; u u_add) { \
|
||||
for (v = v_begin; v v_op v_final; v v_add) { \
|
||||
if (mask->bitmap->getpixel(U, V)) \
|
||||
if (this->bitmap->getpixel(U, V)) \
|
||||
break; \
|
||||
} \
|
||||
if (v == v_final) \
|
||||
@ -442,41 +453,39 @@ static void shrink_mask(Mask* mask)
|
||||
|
||||
int u, v, x1, y1, x2, y2;
|
||||
|
||||
x1 = mask->x;
|
||||
y1 = mask->y;
|
||||
x2 = mask->x+mask->w-1;
|
||||
y2 = mask->y+mask->h-1;
|
||||
x1 = this->x;
|
||||
y1 = this->y;
|
||||
x2 = this->x+this->w-1;
|
||||
y2 = this->y+this->h-1;
|
||||
|
||||
SHRINK_SIDE(0, <, mask->w, ++,
|
||||
0, <, mask->h, ++, u, v, x1++);
|
||||
SHRINK_SIDE(0, <, this->w, ++,
|
||||
0, <, this->h, ++, u, v, x1++);
|
||||
|
||||
SHRINK_SIDE(0, <, mask->h, ++,
|
||||
0, <, mask->w, ++, v, u, y1++);
|
||||
SHRINK_SIDE(0, <, this->h, ++,
|
||||
0, <, this->w, ++, v, u, y1++);
|
||||
|
||||
SHRINK_SIDE(mask->w-1, >, 0, --,
|
||||
0, <, mask->h, ++, u, v, x2--);
|
||||
SHRINK_SIDE(this->w-1, >, 0, --,
|
||||
0, <, this->h, ++, u, v, x2--);
|
||||
|
||||
SHRINK_SIDE(mask->h-1, >, 0, --,
|
||||
0, <, mask->w, ++, v, u, y2--);
|
||||
SHRINK_SIDE(this->h-1, >, 0, --,
|
||||
0, <, this->w, ++, v, u, y2--);
|
||||
|
||||
if ((x1 > x2) || (y1 > y2)) {
|
||||
mask_none(mask);
|
||||
mask_none(this);
|
||||
}
|
||||
else if ((x1 != mask->x) || (x2 != mask->x+mask->w-1) ||
|
||||
(y1 != mask->y) || (y2 != mask->y+mask->h-1)) {
|
||||
Image *image;
|
||||
else if ((x1 != this->x) || (x2 != this->x+this->w-1) ||
|
||||
(y1 != this->y) || (y2 != this->y+this->h-1)) {
|
||||
u = this->x;
|
||||
v = this->y;
|
||||
|
||||
u = mask->x;
|
||||
v = mask->y;
|
||||
this->x = x1;
|
||||
this->y = y1;
|
||||
this->w = x2 - x1 + 1;
|
||||
this->h = y2 - y1 + 1;
|
||||
|
||||
mask->x = x1;
|
||||
mask->y = y1;
|
||||
mask->w = x2 - x1 + 1;
|
||||
mask->h = y2 - y1 + 1;
|
||||
|
||||
image = image_crop(mask->bitmap, mask->x-u, mask->y-v, mask->w, mask->h, 0);
|
||||
image_free(mask->bitmap);
|
||||
mask->bitmap = image;
|
||||
Image* image = image_crop(this->bitmap, this->x-u, this->y-v, this->w, this->h, 0);
|
||||
image_free(this->bitmap);
|
||||
this->bitmap = image;
|
||||
}
|
||||
|
||||
#undef SHRINK_SIDE
|
||||
|
@ -23,10 +23,13 @@
|
||||
|
||||
class Image;
|
||||
|
||||
// Represents the selection (selected pixels, 0/1, 0=non-selected, 1=selected)
|
||||
class Mask : public GfxObj
|
||||
{
|
||||
int m_freeze_count;
|
||||
public:
|
||||
char *name; /* mask name */
|
||||
// TODO private this
|
||||
char* name; /* mask name */
|
||||
int x, y, w, h; /* region bounds */
|
||||
Image* bitmap; /* bitmapped image mask */
|
||||
|
||||
@ -34,6 +37,29 @@ public:
|
||||
Mask(const Mask& mask);
|
||||
virtual ~Mask();
|
||||
|
||||
// Returns true if the mask is completely empty (i.e. nothing
|
||||
// selected)
|
||||
bool is_empty() const {
|
||||
return (!this->bitmap)? true: false;
|
||||
}
|
||||
|
||||
// These functions can be used to disable the automatic call to
|
||||
// "shrink" method (so you can do a lot of modifications without
|
||||
// lossing time shrink the mask in each little operation)
|
||||
void freeze();
|
||||
void unfreeze();
|
||||
|
||||
// Adds the specified rectangle in the mask/selection
|
||||
void add(int x, int y, int w, int h);
|
||||
|
||||
// Reserve a rectangle to draw onto the bitmap (you should call
|
||||
// shrink after you draw in the bitmap)
|
||||
void reserve(int x, int y, int w, int h);
|
||||
|
||||
// Shrinks all sides of the mask to the minimum possible looking at
|
||||
// empty pixels in the bitmap
|
||||
void shrink();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
};
|
||||
@ -42,7 +68,6 @@ Mask* mask_new();
|
||||
Mask* mask_new_copy(const Mask* mask);
|
||||
void mask_free(Mask* mask);
|
||||
|
||||
int mask_is_empty(Mask* mask);
|
||||
void mask_set_name(Mask* mask, const char *name);
|
||||
|
||||
void mask_copy(Mask* mask_dst, const Mask* mask_src);
|
||||
@ -54,7 +79,6 @@ void mask_union(Mask* mask, int x, int y, int w, int h);
|
||||
void mask_subtract(Mask* mask, int x, int y, int w, int h);
|
||||
void mask_intersect(Mask* mask, int x, int y, int w, int h);
|
||||
|
||||
void mask_merge(Mask* dst, const Mask* src);
|
||||
void mask_by_color(Mask* mask, const Image* image, int color, int fuzziness);
|
||||
void mask_crop(Mask* mask, const Image* image);
|
||||
|
||||
|
@ -2225,7 +2225,7 @@ static Mask* read_raw_mask(ase_uint8* raw_data)
|
||||
if (w > 0 && h > 0) {
|
||||
size = (w+7)/8;
|
||||
|
||||
mask_union(mask, x, y, w, h);
|
||||
mask->add(x, y, w, h);
|
||||
for (c=0; c<mask->h; c++)
|
||||
read_raw_data(mask->bitmap->line[c], size);
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ void Undoable::crop_sprite(int x, int y, int w, int h, int bgcolor)
|
||||
if (background_layer)
|
||||
crop_layer(background_layer, 0, 0, m_sprite->w, m_sprite->h, bgcolor);
|
||||
|
||||
if (!mask_is_empty(m_sprite->mask))
|
||||
if (!m_sprite->mask->is_empty())
|
||||
set_mask_position(m_sprite->mask->x-x, m_sprite->mask->y-y);
|
||||
}
|
||||
|
||||
@ -955,7 +955,7 @@ void Undoable::clear_mask(int bgcolor)
|
||||
|
||||
// if the mask is empty then we have to clear the entire image
|
||||
// in the cel
|
||||
if (mask_is_empty(m_sprite->mask)) {
|
||||
if (m_sprite->mask->is_empty()) {
|
||||
// if the layer is the background then we clear the image
|
||||
if (m_sprite->layer->is_background()) {
|
||||
if (is_enabled())
|
||||
|
Loading…
x
Reference in New Issue
Block a user