Added Undoable::crop_sprite/layer/cel.

Added Undoable::replace_stock_image, autocrop.
Added image_shrink_rect function.
Removed autocrop_sprite, CropSprite, CropLayer, and CropCel functions.
This commit is contained in:
David Capello 2008-10-14 03:11:59 +00:00
parent 7a68a1d32b
commit e9c3d46693
21 changed files with 339 additions and 271 deletions

View File

@ -1,11 +1,23 @@
2008-10-13 David A. Capello <davidcapello@gmail.com> 2008-10-13 David A. Capello <davidcapello@gmail.com>
* src/raster/gfxobj.cpp (_gfxobj_set_id): Fixed (the object is
removed from the map before its ID is changed).
* src/raster/stock.cpp (Stock::Stock): Fixed.
* src/raster/undoable.cpp (Undoable::crop_sprite)
(Undoable::crop_layer, Undoable::autocrop_sprite)
(Undoable::replace_stock_image): Added.
* src/raster/image.cpp (image_shrink_rect): Added.
* src/raster/gfxobj.cpp (objects_map): Replaced JList 'objects' * src/raster/gfxobj.cpp (objects_map): Replaced JList 'objects'
by a 'objects_map' (a std::map). by a 'objects_map' (a std::map).
* src/raster/sprite.cpp (~Sprite), * src/raster/sprite.cpp (~Sprite),
src/modules/palettes.cpp (exit_module_palette): Fixed a serious * src/modules/palettes.cpp (exit_module_palette):
bug where palettes were not freed right (jfree instead of * src/commands/cmd_palette_editor.cpp (load_command): Fixed a
serious bug where palettes were not freed right (jfree instead of
palette_free). It leaves dead-pointers in the collection of palette_free). It leaves dead-pointers in the collection of
graphics objects in 'gfxobj.cpp'. graphics objects in 'gfxobj.cpp'.

View File

@ -11,7 +11,8 @@ NEWS
+ Added support to lock lines in special angles with the Shift key, + Added support to lock lines in special angles with the Shift key,
useful to draw in isometric views (feature request #1961397). useful to draw in isometric views (feature request #1961397).
+ Fixed bugs #1958760 and #1958932. + Fixed bugs #1958760 and #1958932.
+ Fixed other bugs (Flatten Layers, File Selector, etc.). + Fixed other serious bugs (Dead-pointers to palettes, Flatten
Layers, File Selector, etc.).
0.6b2 0.6b2
----- -----

View File

@ -19,13 +19,15 @@
#include "config.h" #include "config.h"
#include "commands/commands.h" #include "commands/commands.h"
#include "core/app.h"
#include "modules/gui.h" #include "modules/gui.h"
#include "modules/sprites.h" #include "modules/sprites.h"
#include "raster/image.h" #include "raster/image.h"
#include "raster/layer.h" #include "raster/layer.h"
#include "raster/mask.h" #include "raster/mask.h"
#include "raster/sprite.h" #include "raster/sprite.h"
#include "raster/undo.h" #include "raster/undoable.h"
#include "widgets/colbar.h"
#include "util/autocrop.h" #include "util/autocrop.h"
#include "util/functions.h" #include "util/functions.h"
#include "util/misc.h" #include "util/misc.h"
@ -45,11 +47,16 @@ static bool cmd_crop_sprite_enabled(const char *argument)
static void cmd_crop_sprite_execute(const char *argument) static void cmd_crop_sprite_execute(const char *argument)
{ {
Sprite *sprite = current_sprite; Sprite *sprite = current_sprite;
{
if (undo_is_enabled(sprite->undo)) Undoable undoable(sprite, "Sprite Crop");
undo_set_label(sprite->undo, "Sprite Crop"); undoable.crop_sprite(current_sprite->mask->x,
current_sprite->mask->y,
CropSprite(sprite); current_sprite->mask->w,
current_sprite->mask->h,
colorbar_get_bg_color(app_get_colorbar()));
undoable.commit();
}
sprite_generate_mask_boundaries(sprite);
update_screen_for_sprite(sprite); update_screen_for_sprite(sprite);
} }
@ -65,11 +72,12 @@ static bool cmd_autocrop_sprite_enabled(const char *argument)
static void cmd_autocrop_sprite_execute(const char *argument) static void cmd_autocrop_sprite_execute(const char *argument)
{ {
Sprite *sprite = current_sprite; Sprite *sprite = current_sprite;
{
if (undo_is_enabled(sprite->undo)) Undoable undoable(sprite, "Sprite Autocrop");
undo_set_label(sprite->undo, "Sprite Autocrop"); undoable.autocrop_sprite(colorbar_get_bg_color(app_get_colorbar()));
undoable.commit();
autocrop_sprite(sprite); }
sprite_generate_mask_boundaries(sprite);
update_screen_for_sprite(sprite); update_screen_for_sprite(sprite);
} }

View File

@ -38,7 +38,6 @@ static void cmd_duplicate_sprite_execute(const char *argument)
{ {
JWidget window, src_name, dst_name, flatten; JWidget window, src_name, dst_name, flatten;
Sprite *sprite = current_sprite; Sprite *sprite = current_sprite;
Sprite *sprite_copy;
char buf[1024]; char buf[1024];
/* load the window widget */ /* load the window widget */
@ -64,7 +63,9 @@ static void cmd_duplicate_sprite_execute(const char *argument)
if (jwindow_get_killer(window) == jwidget_find_name(window, "ok")) { if (jwindow_get_killer(window) == jwidget_find_name(window, "ok")) {
set_config_bool("DuplicateSprite", "Flatten", set_config_bool("DuplicateSprite", "Flatten",
jwidget_is_selected(flatten)); jwidget_is_selected(flatten));
// make a copy of the current sprite
Sprite *sprite_copy;
if (jwidget_is_selected(flatten)) if (jwidget_is_selected(flatten))
sprite_copy = sprite_new_flatten_copy(sprite); sprite_copy = sprite_new_flatten_copy(sprite);
else else

View File

@ -292,7 +292,7 @@ static void load_command(JWidget widget)
} }
else { else {
set_new_palette(palette); set_new_palette(palette);
jfree(palette); palette_free(palette);
} }
} }
} }

View File

@ -711,15 +711,15 @@ static Option *option_new(int type, const char *data)
return option; return option;
} }
static void option_free(Option *option) static void option_free(Option* option)
{ {
jfree(option->data); jfree(option->data);
jfree(option); jfree(option);
} }
static AppHook *apphook_new(void (*proc)(void *), void *data) static AppHook *apphook_new(void (*proc)(void*), void* data)
{ {
AppHook *apphook = jnew(AppHook, 1); AppHook* apphook = jnew(AppHook, 1);
if (!apphook) if (!apphook)
return NULL; return NULL;

View File

@ -243,7 +243,7 @@ static bool anieditor_msg_proc(JWidget widget, JMessage msg)
switch (msg->type) { switch (msg->type) {
case JM_DESTROY: case JM_DESTROY:
if (anieditor->layers != NULL) if (anieditor->layers)
jfree(anieditor->layers); jfree(anieditor->layers);
jfree(anieditor); jfree(anieditor);
break; break;

View File

@ -248,16 +248,16 @@ void simple_dotted_mode(BITMAP *bmp, int fg, int bg)
/**********************************************************************/ /**********************************************************************/
/* Set/Restore sub-clip regions */ /* Set/Restore sub-clip regions */
typedef struct CLIP_DATA struct CLIP_DATA
{ {
BITMAP *bmp; BITMAP* bmp;
int cl, ct, cr, cb; int cl, ct, cr, cb;
} CLIP_DATA; };
void *subclip(BITMAP *bmp, int x1, int y1, int x2, int y2) void* subclip(BITMAP* bmp, int x1, int y1, int x2, int y2)
{ {
int cl, ct, cr, cb; int cl, ct, cr, cb;
CLIP_DATA *data; CLIP_DATA* data;
cl = bmp->cl; cl = bmp->cl;
ct = bmp->ct; ct = bmp->ct;
@ -274,7 +274,7 @@ void *subclip(BITMAP *bmp, int x1, int y1, int x2, int y2)
set_clip(bmp, x1, y1, x2, y2); set_clip(bmp, x1, y1, x2, y2);
data = jnew(CLIP_DATA, 1); data = new CLIP_DATA;
data->bmp = bmp; data->bmp = bmp;
data->cl = cl; data->cl = cl;
data->ct = ct; data->ct = ct;
@ -284,11 +284,11 @@ void *subclip(BITMAP *bmp, int x1, int y1, int x2, int y2)
return data; return data;
} }
void backclip(void *_data) void backclip(void* _data)
{ {
CLIP_DATA* data = reinterpret_cast<CLIP_DATA*>(_data); CLIP_DATA* data = reinterpret_cast<CLIP_DATA*>(_data);
set_clip(data->bmp, data->cl, data->ct, data->cr, data->cb); set_clip(data->bmp, data->cl, data->ct, data->cr, data->cb);
jfree(data); delete data;
} }
/**********************************************************************/ /**********************************************************************/
@ -302,8 +302,8 @@ struct RectTracker
int *pixel; int *pixel;
}; };
static void do_rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int c, static void do_rect(BITMAP* bmp, int x1, int y1, int x2, int y2, int c,
void (*proc)(BITMAP *bmp, int x, int y, int c)) void (*proc)(BITMAP* bmp, int x, int y, int c))
{ {
int x, y, u1, u2, v1, v2; int x, y, u1, u2, v1, v2;
@ -338,25 +338,25 @@ static void do_rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int c,
} }
} }
static void count_rect(BITMAP *bmp, int x, int y, int c) static void count_rect(BITMAP* bmp, int x, int y, int c)
{ {
RectTracker *data = (RectTracker *)c; RectTracker* data = (RectTracker*)c;
data->npixel++; data->npixel++;
} }
static void save_rect(BITMAP *bmp, int x, int y, int c) static void save_rect(BITMAP* bmp, int x, int y, int c)
{ {
RectTracker *data = (RectTracker *)c; RectTracker* data = (RectTracker*)c;
data->pixel[data->npixel++] = getpixel(bmp, x, y); data->pixel[data->npixel++] = getpixel(bmp, x, y);
} }
static void restore_rect(BITMAP *bmp, int x, int y, int c) static void restore_rect(BITMAP* bmp, int x, int y, int c)
{ {
RectTracker *data = (RectTracker *)c; RectTracker* data = (RectTracker*)c;
putpixel(bmp, x, y, data->pixel[data->npixel++]); putpixel(bmp, x, y, data->pixel[data->npixel++]);
} }
RectTracker *rect_tracker_new(BITMAP *bmp, int x1, int y1, int x2, int y2) RectTracker* rect_tracker_new(BITMAP* bmp, int x1, int y1, int x2, int y2)
{ {
RectTracker *data; RectTracker *data;
int x, y; int x, y;
@ -366,7 +366,7 @@ RectTracker *rect_tracker_new(BITMAP *bmp, int x1, int y1, int x2, int y2)
if (x1 > x2) { x = x1; x1 = x2; x2 = x; } if (x1 > x2) { x = x1; x1 = x2; x2 = x; }
if (y1 > y2) { y = y1; y1 = y2; y2 = y; } if (y1 > y2) { y = y1; y1 = y2; y2 = y; }
data = jnew(RectTracker, 1); data = new RectTracker;
data->bmp = bmp; data->bmp = bmp;
data->x1 = x1; data->x1 = x1;
@ -378,7 +378,7 @@ RectTracker *rect_tracker_new(BITMAP *bmp, int x1, int y1, int x2, int y2)
do_rect(bmp, x1, y1, x2, y2, (int)data, count_rect); do_rect(bmp, x1, y1, x2, y2, (int)data, count_rect);
if (data->npixel > 0) if (data->npixel > 0)
data->pixel = (int*)jmalloc(sizeof(int) * data->npixel); data->pixel = new int[data->npixel];
else else
data->pixel = NULL; data->pixel = NULL;
@ -390,7 +390,7 @@ RectTracker *rect_tracker_new(BITMAP *bmp, int x1, int y1, int x2, int y2)
return data; return data;
} }
void rect_tracker_free(RectTracker *data) void rect_tracker_free(RectTracker* data)
{ {
jmouse_hide(); jmouse_hide();
@ -398,9 +398,8 @@ void rect_tracker_free(RectTracker *data)
do_rect(data->bmp, data->x1, data->y1, data->x2, data->y2, do_rect(data->bmp, data->x1, data->y1, data->x2, data->y2,
(int)data, restore_rect); (int)data, restore_rect);
if (data->pixel != NULL) delete[] data->pixel;
jfree(data->pixel); delete data;
jfree(data);
jmouse_show(); jmouse_show();
} }

View File

@ -225,7 +225,7 @@ ImageRef *images_ref_get_from_sprite(Sprite* sprite, int target, bool write)
return images_ref_get_from_layer(sprite, layer, target, write); return images_ref_get_from_layer(sprite, layer, target, write);
} }
void images_ref_free(ImageRef *image_ref) void images_ref_free(ImageRef* image_ref)
{ {
ImageRef *p, *next; ImageRef *p, *next;

View File

@ -32,6 +32,9 @@ static JMutex objects_mutex;
static gfxobj_id object_id = 0; // last object ID created static gfxobj_id object_id = 0; // last object ID created
static std::map<gfxobj_id, GfxObj*> objects_map; // graphics objects map static std::map<gfxobj_id, GfxObj*> objects_map; // graphics objects map
static void insert_gfxobj(GfxObj* gfxobj);
static void erase_gfxobj(GfxObj* gfxobj);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
bool gfxobj_init() bool gfxobj_init()
@ -46,7 +49,6 @@ bool gfxobj_init()
void gfxobj_exit() void gfxobj_exit()
{ {
assert(objects_map.empty()); assert(objects_map.empty());
jmutex_free(objects_mutex); jmutex_free(objects_mutex);
} }
@ -69,14 +71,7 @@ GfxObj::~GfxObj()
{ {
// we have to remove this object from the map // we have to remove this object from the map
jmutex_lock(objects_mutex); jmutex_lock(objects_mutex);
{ erase_gfxobj(this);
std::map<gfxobj_id, GfxObj*>::iterator
it = objects_map.find(this->id);
assert(it != objects_map.end());
objects_map.erase(it);
}
jmutex_unlock(objects_mutex); jmutex_unlock(objects_mutex);
} }
@ -88,7 +83,7 @@ void GfxObj::assign_id()
this->id = ++object_id; this->id = ++object_id;
// and here we add the object in the map of graphics-objects // and here we add the object in the map of graphics-objects
objects_map.insert(std::make_pair(this->id, this)); insert_gfxobj(this);
} }
jmutex_unlock(objects_mutex); jmutex_unlock(objects_mutex);
} }
@ -115,7 +110,29 @@ GfxObj* gfxobj_find(gfxobj_id id)
void _gfxobj_set_id(GfxObj* gfxobj, gfxobj_id id) void _gfxobj_set_id(GfxObj* gfxobj, gfxobj_id id)
{ {
assert(gfxobj_find(gfxobj->id) == gfxobj);
assert(gfxobj_find(id) == NULL); assert(gfxobj_find(id) == NULL);
gfxobj->id = id; jmutex_lock(objects_mutex);
erase_gfxobj(gfxobj); // remove the object
gfxobj->id = id; // change the ID
insert_gfxobj(gfxobj); // insert the object again in the map
jmutex_unlock(objects_mutex);
}
//////////////////////////////////////////////////////////////////////
static void insert_gfxobj(GfxObj* gfxobj)
{
objects_map.insert(std::make_pair(gfxobj->id, gfxobj));
}
static void erase_gfxobj(GfxObj* gfxobj)
{
std::map<gfxobj_id, GfxObj*>::iterator
it = objects_map.find(gfxobj->id);
assert(it != objects_map.end());
objects_map.erase(it);
} }

View File

@ -545,3 +545,47 @@ int image_count_diff(const Image* i1, const Image* i2)
return diff; return diff;
} }
bool image_shrink_rect(Image *image, int *x1, int *y1, int *x2, int *y2, int refpixel)
{
#define SHRINK_SIDE(u_begin, u_op, u_final, u_add, \
v_begin, v_op, v_final, v_add, U, V, var) \
do { \
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 (image->method->getpixel (image, U, V) != refpixel) \
break; \
} \
if (v == v_final) \
var; \
else \
break; \
} \
} while (0)
int u, v;
*x1 = 0;
*y1 = 0;
*x2 = image->w-1;
*y2 = image->h-1;
SHRINK_SIDE(0, <, image->w, ++,
0, <, image->h, ++, u, v, (*x1)++);
SHRINK_SIDE(0, <, image->h, ++,
0, <, image->w, ++, v, u, (*y1)++);
SHRINK_SIDE(image->w-1, >, 0, --,
0, <, image->h, ++, u, v, (*x2)--);
SHRINK_SIDE(image->h-1, >, 0, --,
0, <, image->w, ++, v, u, (*y2)--);
if ((*x1 > *x2) || (*y1 > *y2))
return false;
else
return true;
#undef SHRINK_SIDE
}

View File

@ -138,5 +138,6 @@ void image_to_allegro(Image* image, BITMAP* bmp, int x, int y);
void image_convert(Image* dst, const Image* src); void image_convert(Image* dst, const Image* src);
int image_count_diff(const Image* i1, const Image* i2); int image_count_diff(const Image* i1, const Image* i2);
bool image_shrink_rect(Image *image, int *x1, int *y1, int *x2, int *y2, int refpixel);
#endif /* RASTER_IMAGE_H */ #endif /* RASTER_IMAGE_H */

View File

@ -446,6 +446,9 @@ void sprite_set_format_options(Sprite* sprite, struct FormatOptions *format_opti
void sprite_set_size(Sprite* sprite, int w, int h) void sprite_set_size(Sprite* sprite, int w, int h)
{ {
assert(w > 0);
assert(h > 0);
sprite->w = w; sprite->w = w;
sprite->h = h; sprite->h = h;
} }

View File

@ -41,8 +41,10 @@ Stock::Stock(const Stock& stock)
: GfxObj(stock) : GfxObj(stock)
{ {
this->imgtype = stock.imgtype; this->imgtype = stock.imgtype;
this->nimage = 0;
this->image = NULL;
for (int c=this->nimage; c<stock.nimage; ++c) { for (int c=0; c<stock.nimage; ++c) {
if (!stock.image[c]) if (!stock.image[c])
stock_add_image(this, NULL); stock_add_image(this, NULL);
else { else {
@ -58,7 +60,7 @@ Stock::Stock(const Stock& stock)
Stock::~Stock() Stock::~Stock()
{ {
for (int i=0; i<this->nimage; i++) { for (int i=0; i<this->nimage; i++) {
if (this->image[i] != NULL) if (this->image[i])
image_free(this->image[i]); image_free(this->image[i]);
} }
jfree(this->image); jfree(this->image);

View File

@ -627,7 +627,6 @@ static void chunk_image_new(UndoStream* stream, Image* image, int x, int y, int
chunk->y = y; chunk->y = y;
chunk->w = w; chunk->w = w;
chunk->h = h; chunk->h = h;
/* chunk->data = jmalloc(size*h); */
ptr = chunk->data; ptr = chunk->data;
for (v=0; v<h; ++v) { for (v=0; v<h; ++v) {
@ -636,11 +635,6 @@ static void chunk_image_new(UndoStream* stream, Image* image, int x, int y, int
} }
} }
/* static void chunk_image_free(UndoChunkImage* chunk) */
/* { */
/* jfree(chunk->data); */
/* } */
static void chunk_image_invert(UndoStream* stream, UndoChunkImage* chunk, int state) static void chunk_image_invert(UndoStream* stream, UndoChunkImage* chunk, int state)
{ {
unsigned int id = chunk->image_id; unsigned int id = chunk->image_id;
@ -914,7 +908,7 @@ void undo_replace_image(Undo* undo, Stock *stock, int image_index)
static void chunk_replace_image_new(UndoStream* stream, Stock *stock, int image_index) static void chunk_replace_image_new(UndoStream* stream, Stock *stock, int image_index)
{ {
Image* image = stock->image[image_index]; Image* image = stock_get_image(stock, image_index);
UndoChunkReplaceImage* chunk = (UndoChunkReplaceImage* ) UndoChunkReplaceImage* chunk = (UndoChunkReplaceImage* )
undo_chunk_new(stream, undo_chunk_new(stream,
UNDO_TYPE_REPLACE_IMAGE, UNDO_TYPE_REPLACE_IMAGE,
@ -930,17 +924,21 @@ static void chunk_replace_image_invert(UndoStream* stream, UndoChunkReplaceImage
{ {
unsigned long stock_id = chunk->stock_id; unsigned long stock_id = chunk->stock_id;
unsigned long image_index = chunk->image_index; unsigned long image_index = chunk->image_index;
Stock *stock = (Stock *)gfxobj_find(stock_id); Stock* stock = (Stock*)gfxobj_find(stock_id);
if (stock) { if (stock) {
// read the image to be restored from the chunk
Image* image = read_raw_image(chunk->data); Image* image = read_raw_image(chunk->data);
// save the current image in the (redo) stream
chunk_replace_image_new(stream, stock, image_index); chunk_replace_image_new(stream, stock, image_index);
Image* old_image = stock_get_image(stock, image_index);
if (stock->image[image_index]) // replace the image in the stock
image_free(stock->image[image_index]);
stock_replace_image(stock, image_index, image); stock_replace_image(stock, image_index, image);
// destroy the old image
image_free(old_image);
} }
} }

View File

@ -118,6 +118,69 @@ void Undoable::set_current_layer(Layer* layer)
sprite_set_layer(sprite, layer); sprite_set_layer(sprite, layer);
} }
void Undoable::set_sprite_size(int w, int h)
{
assert(w > 0);
assert(h > 0);
if (is_enabled()) {
undo_int(sprite->undo, sprite, &sprite->w);
undo_int(sprite->undo, sprite, &sprite->h);
}
sprite_set_size(sprite, w, h);
}
void Undoable::crop_sprite(int x, int y, int w, int h, int bgcolor)
{
set_sprite_size(w, h);
displace_layers(sprite->set, -x, -y);
Layer *background_layer = sprite_get_background_layer(sprite);
if (background_layer)
crop_layer(background_layer, 0, 0, sprite->w, sprite->h, bgcolor);
if (!mask_is_empty(sprite->mask))
set_mask_position(sprite->mask->x-x, sprite->mask->y-y);
}
void Undoable::autocrop_sprite(int bgcolor)
{
int old_frame = sprite->frame;
int x1, y1, x2, y2;
int u1, v1, u2, v2;
x1 = y1 = INT_MAX;
x2 = y2 = INT_MIN;
Image* image = image_new(sprite->imgtype, sprite->w, sprite->h);
for (sprite->frame=0; sprite->frame<sprite->frames; sprite->frame++) {
image_clear(image, 0);
sprite_render(sprite, image, 0, 0);
// TODO configurable (what color pixel to use as "refpixel",
// here we are using the top-left pixel by default)
if (image_shrink_rect(image, &u1, &v1, &u2, &v2,
image_getpixel(image, 0, 0))) {
x1 = MIN(x1, u1);
y1 = MIN(y1, v1);
x2 = MAX(x2, u2);
y2 = MAX(y2, v2);
}
}
sprite->frame = old_frame;
image_free(image);
// do nothing
if (x1 > x2 || y1 > y2)
return;
crop_sprite(x1, y1, x2-x1+1, y2-y1+1, bgcolor);
}
/** /**
* Adds a new image in the stock. * Adds a new image in the stock.
* *
@ -154,6 +217,22 @@ void Undoable::remove_image_from_stock(int image_index)
image_free(image); image_free(image);
} }
void Undoable::replace_stock_image(int image_index, Image* new_image)
{
// get the current image in the 'image_index' position
Image* old_image = stock_get_image(sprite->stock, image_index);
assert(old_image);
// replace the image in the stock
if (is_enabled())
undo_replace_image(sprite->undo, sprite->stock, image_index);
stock_replace_image(sprite->stock, image_index, new_image);
// destroy the old image
image_free(old_image);
}
/** /**
* Creates a new transparent layer. * Creates a new transparent layer.
*/ */
@ -221,6 +300,47 @@ void Undoable::move_layer_after(Layer* layer, Layer* after_this)
layer_move_layer(layer->parent_layer, layer, after_this); layer_move_layer(layer->parent_layer, layer, after_this);
} }
void Undoable::crop_layer(Layer* layer, int x, int y, int w, int h, int bgcolor)
{
JLink link;
if (!layer_is_background(layer))
bgcolor = 0;
JI_LIST_FOR_EACH(layer->cels, link) {
Cel* cel = reinterpret_cast<Cel*>(link->data);
crop_cel(cel, x, y, w, h, bgcolor);
}
}
/**
* Moves every frame in @a layer with the offset (@a dx, @a dy).
*/
void Undoable::displace_layers(Layer* layer, int dx, int dy)
{
switch (layer->type) {
case GFXOBJ_LAYER_IMAGE: {
Cel* cel;
JLink link;
JI_LIST_FOR_EACH(layer->cels, link) {
cel = reinterpret_cast<Cel*>(link->data);
set_cel_position(cel, cel->x+dx, cel->y+dy);
}
break;
}
case GFXOBJ_LAYER_SET: {
JLink link;
JI_LIST_FOR_EACH(layer->layers, link)
displace_layers(reinterpret_cast<Layer*>(link->data), dx, dy);
break;
}
}
}
void Undoable::new_frame() void Undoable::new_frame()
{ {
// add a new cel to every layer // add a new cel to every layer
@ -399,6 +519,19 @@ void Undoable::set_cel_frame_position(Cel* cel, int frame)
cel->frame = frame; cel->frame = frame;
} }
void Undoable::set_cel_position(Cel* cel, int x, int y)
{
assert(cel);
if (is_enabled()) {
undo_int(sprite->undo, cel, &cel->x);
undo_int(sprite->undo, cel, &cel->y);
}
cel->x = x;
cel->y = y;
}
void Undoable::set_frame_duration(int frame, int msecs) void Undoable::set_frame_duration(int frame, int msecs)
{ {
if (is_enabled()) if (is_enabled())
@ -509,6 +642,21 @@ Cel* Undoable::get_current_cel()
return NULL; return NULL;
} }
void Undoable::crop_cel(Cel* cel, int x, int y, int w, int h, int bgcolor)
{
Image* cel_image = stock_get_image(sprite->stock, cel->image);
assert(cel_image);
// create the new image through a crop
Image* new_image = image_crop(cel_image, x-cel->x, y-cel->y, w, h, bgcolor);
// replace the image in the stock that is pointed by the cel
replace_stock_image(cel->image, new_image);
// update the cel's position
set_cel_position(cel, x, y);
}
Image* Undoable::get_cel_image(Cel* cel) Image* Undoable::get_cel_image(Cel* cel)
{ {
if (cel && cel->image >= 0 && cel->image < sprite->stock->nimage) if (cel && cel->image >= 0 && cel->image < sprite->stock->nimage)
@ -577,3 +725,27 @@ void Undoable::clear_mask(int bgcolor)
} }
} }
void Undoable::copy_to_current_mask(Mask* mask)
{
assert(sprite->mask);
assert(mask);
if (is_enabled())
undo_set_mask(sprite->undo, sprite);
mask_copy(sprite->mask, mask);
}
void Undoable::set_mask_position(int x, int y)
{
assert(sprite->mask);
if (is_enabled()) {
undo_int(sprite->undo, sprite->mask, &sprite->mask->x);
undo_int(sprite->undo, sprite->mask, &sprite->mask->y);
}
sprite->mask->x = x;
sprite->mask->y = y;
}

View File

@ -47,15 +47,21 @@ public:
void set_number_of_frames(int frames); void set_number_of_frames(int frames);
void set_current_frame(int frame); void set_current_frame(int frame);
void set_current_layer(Layer* layer); void set_current_layer(Layer* layer);
void set_sprite_size(int w, int h);
void crop_sprite(int x, int y, int w, int h, int bgcolor);
void autocrop_sprite(int bgcolor);
// for images in stock // for images in stock
int add_image_in_stock(Image* image); int add_image_in_stock(Image* image);
void remove_image_from_stock(int image_index); void remove_image_from_stock(int image_index);
void replace_stock_image(int image_index, Image* new_image);
// for layers // for layers
Layer* new_layer(); Layer* new_layer();
void remove_layer(Layer* layer); void remove_layer(Layer* layer);
void move_layer_after(Layer *layer, Layer *after_this); void move_layer_after(Layer *layer, Layer *after_this);
void crop_layer(Layer* layer, int x, int y, int w, int h, int bgcolor);
void displace_layers(Layer* layer, int dx, int dy);
// for frames // for frames
void new_frame(); void new_frame();
@ -72,12 +78,18 @@ public:
void add_cel(Layer* layer, Cel* cel); void add_cel(Layer* layer, Cel* cel);
void remove_cel(Layer* layer, Cel* cel); void remove_cel(Layer* layer, Cel* cel);
void set_cel_frame_position(Cel* cel, int frame); void set_cel_frame_position(Cel* cel, int frame);
void set_cel_position(Cel* cel, int x, int y);
Cel* get_current_cel(); Cel* get_current_cel();
void crop_cel(Cel* cel, int x, int y, int w, int h, int bgcolor);
// for image // for image
Image* get_cel_image(Cel* cel); Image* get_cel_image(Cel* cel);
void clear_mask(int bgcolor); void clear_mask(int bgcolor);
// for mask
void copy_to_current_mask(Mask* mask);
void set_mask_position(int x, int y);
}; };
#endif /* RASTER_UNDOABLE_H */ #endif /* RASTER_UNDOABLE_H */

View File

@ -24,56 +24,6 @@
#include "util/autocrop.h" #include "util/autocrop.h"
#include "util/functions.h" #include "util/functions.h"
void autocrop_sprite(Sprite *sprite)
{
if (sprite != NULL) {
int old_frame = sprite->frame;
Mask *old_mask = sprite->mask;
Mask *mask;
Image *image;
int x1, y1, x2, y2;
int u1, v1, u2, v2;
x1 = y1 = INT_MAX;
x2 = y2 = INT_MIN;
image = image_new(sprite->imgtype, sprite->w, sprite->h);
if (!image)
return;
for (sprite->frame=0; sprite->frame<sprite->frames; sprite->frame++) {
image_clear(image, 0);
sprite_render(sprite, image, 0, 0);
/* TODO configurable (what color pixel to use as "refpixel",
here we are using the top-left pixel by default) */
if (get_shrink_rect(&u1, &v1, &u2, &v2,
image, image_getpixel (image, 0, 0))) {
x1 = MIN(x1, u1);
y1 = MIN(y1, v1);
x2 = MAX(x2, u2);
y2 = MAX(y2, v2);
}
}
sprite->frame = old_frame;
image_free(image);
/* do nothing */
if (x1 > x2 || y1 > y2)
return;
mask = mask_new();
mask_replace(mask, x1, y1, x2-x1+1, y2-y1+1);
sprite->mask = mask;
CropSprite(sprite);
sprite->mask = old_mask;
sprite_generate_mask_boundaries(sprite);
}
}
bool get_shrink_rect(int *x1, int *y1, int *x2, int *y2, bool get_shrink_rect(int *x1, int *y1, int *x2, int *y2,
Image *image, int refpixel) Image *image, int refpixel)
{ {

View File

@ -19,8 +19,6 @@
#ifndef UTIL_AUTOCROP_H #ifndef UTIL_AUTOCROP_H
#define UTIL_AUTOCROP_H #define UTIL_AUTOCROP_H
void autocrop_sprite(Sprite *sprite);
bool get_shrink_rect(int *x1, int *y1, int *x2, int *y2, bool get_shrink_rect(int *x1, int *y1, int *x2, int *y2,
Image *image, int refpixel); Image *image, int refpixel);
bool get_shrink_rect2(int *x1, int *y1, int *x2, int *y2, bool get_shrink_rect2(int *x1, int *y1, int *x2, int *y2,

View File

@ -35,8 +35,6 @@
/* Sprite */ /* Sprite */
/*===================================================================*/ /*===================================================================*/
static void displace_layers(Undo *undo, Layer *layer, int x, int y);
/** /**
* Creates a new sprite with the given dimension with one transparent * Creates a new sprite with the given dimension with one transparent
* layer called "Layer 1". * layer called "Layer 1".
@ -142,78 +140,6 @@ void SetSprite(Sprite *sprite)
set_current_sprite(sprite); set_current_sprite(sprite);
} }
void CropSprite(Sprite *sprite)
{
if ((sprite != NULL) &&
(!mask_is_empty(sprite->mask))) {
if (undo_is_enabled(sprite->undo)) {
undo_open(sprite->undo);
undo_int(sprite->undo, (GfxObj *)sprite, &sprite->w);
undo_int(sprite->undo, (GfxObj *)sprite, &sprite->h);
}
sprite_set_size(sprite, sprite->mask->w, sprite->mask->h);
displace_layers(sprite->undo, sprite->set,
-sprite->mask->x, -sprite->mask->y);
{
Layer *background_layer = sprite_get_background_layer(sprite);
if (background_layer != NULL) {
CropLayer(background_layer, 0, 0, sprite->w, sprite->h);
}
}
if (undo_is_enabled(sprite->undo)) {
undo_int(sprite->undo, (GfxObj *)sprite->mask, &sprite->mask->x);
undo_int(sprite->undo, (GfxObj *)sprite->mask, &sprite->mask->y);
}
sprite->mask->x = 0;
sprite->mask->y = 0;
if (undo_is_enabled(sprite->undo))
undo_close(sprite->undo);
sprite_generate_mask_boundaries(sprite);
}
}
/**
* Moves every frame in "layer" with the offset "x"/"y".
*/
static void displace_layers(Undo *undo, Layer *layer, int x, int y)
{
switch (layer->type) {
case GFXOBJ_LAYER_IMAGE: {
Cel *cel;
JLink link;
JI_LIST_FOR_EACH(layer->cels, link) {
cel = reinterpret_cast<Cel*>(link->data);
if (undo_is_enabled(undo)) {
undo_int(undo, (GfxObj *)cel, &cel->x);
undo_int(undo, (GfxObj *)cel, &cel->y);
}
cel->x += x;
cel->y += y;
}
break;
}
case GFXOBJ_LAYER_SET: {
JLink link;
JI_LIST_FOR_EACH(layer->layers, link)
displace_layers(undo, reinterpret_cast<Layer*>(link->data), x, y);
break;
}
}
}
/*===================================================================*/ /*===================================================================*/
/* Layer */ /* Layer */
/*===================================================================*/ /*===================================================================*/
@ -391,41 +317,6 @@ Layer *FlattenLayers(Sprite *sprite)
return background; return background;
} }
void CropLayer(Layer *layer, int x, int y, int w, int h)
{
Sprite *sprite = layer->sprite;
Cel *cel;
Image *image;
Image *new_image;
JLink link;
JI_LIST_FOR_EACH(layer->cels, link) {
cel = reinterpret_cast<Cel*>(link->data);
image = stock_get_image(sprite->stock, cel->image);
if (image == NULL)
continue;
new_image = image_crop(image, x-cel->x, y-cel->y, w, h,
app_get_color_to_clear_layer(layer));
if (new_image == NULL) {
console_printf(_("Not enough memory\n"));
return;
}
if (undo_is_enabled(sprite->undo)) {
undo_replace_image(sprite->undo, sprite->stock, cel->image);
undo_int(sprite->undo, (GfxObj *)cel, &cel->x);
undo_int(sprite->undo, (GfxObj *)cel, &cel->y);
}
cel->x = x;
cel->y = y;
stock_replace_image(sprite->stock, cel->image, new_image);
image_free(image);
}
}
/** /**
* Converts the selected layer in a `Background' layer. * Converts the selected layer in a `Background' layer.
*/ */
@ -667,38 +558,3 @@ void RemoveCel(Layer *layer, Cel *cel)
cel_free(cel); cel_free(cel);
} }
} }
void CropCel()
{
Sprite *sprite = current_sprite;
Image *image = GetImage(current_sprite);
if ((sprite) && (!mask_is_empty (sprite->mask)) && (image)) {
Cel *cel = layer_get_cel(sprite->layer, sprite->frame);
/* undo */
if (undo_is_enabled(sprite->undo)) {
undo_open(sprite->undo);
undo_int(sprite->undo, (GfxObj *)cel, &cel->x);
undo_int(sprite->undo, (GfxObj *)cel, &cel->y);
undo_replace_image(sprite->undo, sprite->stock, cel->image);
undo_close(sprite->undo);
}
/* replace the image */
sprite->stock->image[cel->image] =
image_crop(image,
sprite->mask->x-cel->x,
sprite->mask->y-cel->y,
sprite->mask->w,
sprite->mask->h, 0);
image_free(image); /* destroy the old image */
/* change the cel position */
cel->x = sprite->mask->x;
cel->y = sprite->mask->y;
update_screen_for_sprite(sprite);
}
}

View File

@ -33,8 +33,6 @@ void SaveSprite(const char* filename);
void SetSprite(Sprite* sprite); void SetSprite(Sprite* sprite);
void CropSprite(Sprite* sprite);
/*===================================================================*/ /*===================================================================*/
/* Layer */ /* Layer */
/*===================================================================*/ /*===================================================================*/
@ -45,8 +43,6 @@ char *GetUniqueLayerName(Sprite* sprite);
Layer* FlattenLayers(Sprite* sprite); Layer* FlattenLayers(Sprite* sprite);
void CropLayer(Layer* layer, int x, int y, int w, int h);
void BackgroundFromLayer(Sprite* sprite); void BackgroundFromLayer(Sprite* sprite);
void LayerFromBackground(Sprite* sprite); void LayerFromBackground(Sprite* sprite);
@ -56,6 +52,4 @@ void LayerFromBackground(Sprite* sprite);
void RemoveCel(Layer* layer, Cel* cel); void RemoveCel(Layer* layer, Cel* cel);
void CropCel();
#endif /* UTIL_FUNCTIONS_H */ #endif /* UTIL_FUNCTIONS_H */