diff --git a/ChangeLog b/ChangeLog index 0d41dea52..2a2e0db44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,23 @@ 2008-10-13 David A. Capello + * 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' by a 'objects_map' (a std::map). * src/raster/sprite.cpp (~Sprite), - src/modules/palettes.cpp (exit_module_palette): Fixed a serious - bug where palettes were not freed right (jfree instead of + * src/modules/palettes.cpp (exit_module_palette): + * 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 graphics objects in 'gfxobj.cpp'. diff --git a/NEWS.txt b/NEWS.txt index 36d076acb..996a37d03 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -11,7 +11,8 @@ NEWS + Added support to lock lines in special angles with the Shift key, useful to draw in isometric views (feature request #1961397). + 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 ----- diff --git a/src/commands/cmd_crop.cpp b/src/commands/cmd_crop.cpp index 9173d99b5..0143c308e 100644 --- a/src/commands/cmd_crop.cpp +++ b/src/commands/cmd_crop.cpp @@ -19,13 +19,15 @@ #include "config.h" #include "commands/commands.h" +#include "core/app.h" #include "modules/gui.h" #include "modules/sprites.h" #include "raster/image.h" #include "raster/layer.h" #include "raster/mask.h" #include "raster/sprite.h" -#include "raster/undo.h" +#include "raster/undoable.h" +#include "widgets/colbar.h" #include "util/autocrop.h" #include "util/functions.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) { Sprite *sprite = current_sprite; - - if (undo_is_enabled(sprite->undo)) - undo_set_label(sprite->undo, "Sprite Crop"); - - CropSprite(sprite); + { + Undoable undoable(sprite, "Sprite Crop"); + undoable.crop_sprite(current_sprite->mask->x, + current_sprite->mask->y, + 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); } @@ -65,11 +72,12 @@ static bool cmd_autocrop_sprite_enabled(const char *argument) static void cmd_autocrop_sprite_execute(const char *argument) { Sprite *sprite = current_sprite; - - if (undo_is_enabled(sprite->undo)) - undo_set_label(sprite->undo, "Sprite Autocrop"); - - autocrop_sprite(sprite); + { + Undoable undoable(sprite, "Sprite Autocrop"); + undoable.autocrop_sprite(colorbar_get_bg_color(app_get_colorbar())); + undoable.commit(); + } + sprite_generate_mask_boundaries(sprite); update_screen_for_sprite(sprite); } diff --git a/src/commands/cmd_duplicate_sprite.cpp b/src/commands/cmd_duplicate_sprite.cpp index 616acfe38..439d52702 100644 --- a/src/commands/cmd_duplicate_sprite.cpp +++ b/src/commands/cmd_duplicate_sprite.cpp @@ -38,7 +38,6 @@ static void cmd_duplicate_sprite_execute(const char *argument) { JWidget window, src_name, dst_name, flatten; Sprite *sprite = current_sprite; - Sprite *sprite_copy; char buf[1024]; /* 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")) { set_config_bool("DuplicateSprite", "Flatten", jwidget_is_selected(flatten)); - + + // make a copy of the current sprite + Sprite *sprite_copy; if (jwidget_is_selected(flatten)) sprite_copy = sprite_new_flatten_copy(sprite); else diff --git a/src/commands/cmd_palette_editor.cpp b/src/commands/cmd_palette_editor.cpp index 08b4bbef3..28bd463e1 100644 --- a/src/commands/cmd_palette_editor.cpp +++ b/src/commands/cmd_palette_editor.cpp @@ -292,7 +292,7 @@ static void load_command(JWidget widget) } else { set_new_palette(palette); - jfree(palette); + palette_free(palette); } } } diff --git a/src/core/app.cpp b/src/core/app.cpp index ff2383152..53c0aa3b2 100644 --- a/src/core/app.cpp +++ b/src/core/app.cpp @@ -711,15 +711,15 @@ static Option *option_new(int type, const char *data) return option; } -static void option_free(Option *option) +static void option_free(Option* option) { jfree(option->data); 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) return NULL; diff --git a/src/dialogs/aniedit.cpp b/src/dialogs/aniedit.cpp index ab6e8c456..4f17dc82d 100644 --- a/src/dialogs/aniedit.cpp +++ b/src/dialogs/aniedit.cpp @@ -243,7 +243,7 @@ static bool anieditor_msg_proc(JWidget widget, JMessage msg) switch (msg->type) { case JM_DESTROY: - if (anieditor->layers != NULL) + if (anieditor->layers) jfree(anieditor->layers); jfree(anieditor); break; diff --git a/src/modules/gfx.cpp b/src/modules/gfx.cpp index 64e6705fa..f1c50a454 100644 --- a/src/modules/gfx.cpp +++ b/src/modules/gfx.cpp @@ -248,16 +248,16 @@ void simple_dotted_mode(BITMAP *bmp, int fg, int bg) /**********************************************************************/ /* Set/Restore sub-clip regions */ -typedef struct CLIP_DATA +struct CLIP_DATA { - BITMAP *bmp; + BITMAP* bmp; 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; - CLIP_DATA *data; + CLIP_DATA* data; cl = bmp->cl; 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); - data = jnew(CLIP_DATA, 1); + data = new CLIP_DATA; data->bmp = bmp; data->cl = cl; data->ct = ct; @@ -284,11 +284,11 @@ void *subclip(BITMAP *bmp, int x1, int y1, int x2, int y2) return data; } -void backclip(void *_data) +void backclip(void* _data) { CLIP_DATA* data = reinterpret_cast(_data); set_clip(data->bmp, data->cl, data->ct, data->cr, data->cb); - jfree(data); + delete data; } /**********************************************************************/ @@ -302,8 +302,8 @@ struct RectTracker int *pixel; }; -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)) +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)) { 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++; } -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); } -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++]); } -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; 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 (y1 > y2) { y = y1; y1 = y2; y2 = y; } - data = jnew(RectTracker, 1); + data = new RectTracker; data->bmp = bmp; 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); if (data->npixel > 0) - data->pixel = (int*)jmalloc(sizeof(int) * data->npixel); + data->pixel = new int[data->npixel]; else data->pixel = NULL; @@ -390,7 +390,7 @@ RectTracker *rect_tracker_new(BITMAP *bmp, int x1, int y1, int x2, int y2) return data; } -void rect_tracker_free(RectTracker *data) +void rect_tracker_free(RectTracker* data) { jmouse_hide(); @@ -398,9 +398,8 @@ void rect_tracker_free(RectTracker *data) do_rect(data->bmp, data->x1, data->y1, data->x2, data->y2, (int)data, restore_rect); - if (data->pixel != NULL) - jfree(data->pixel); - jfree(data); + delete[] data->pixel; + delete data; jmouse_show(); } diff --git a/src/modules/sprites.cpp b/src/modules/sprites.cpp index 186889689..cb90e0ef4 100644 --- a/src/modules/sprites.cpp +++ b/src/modules/sprites.cpp @@ -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); } -void images_ref_free(ImageRef *image_ref) +void images_ref_free(ImageRef* image_ref) { ImageRef *p, *next; diff --git a/src/raster/gfxobj.cpp b/src/raster/gfxobj.cpp index da9f77a6c..51cae83a0 100644 --- a/src/raster/gfxobj.cpp +++ b/src/raster/gfxobj.cpp @@ -32,6 +32,9 @@ static JMutex objects_mutex; static gfxobj_id object_id = 0; // last object ID created static std::map objects_map; // graphics objects map +static void insert_gfxobj(GfxObj* gfxobj); +static void erase_gfxobj(GfxObj* gfxobj); + ////////////////////////////////////////////////////////////////////// bool gfxobj_init() @@ -46,7 +49,6 @@ bool gfxobj_init() void gfxobj_exit() { assert(objects_map.empty()); - jmutex_free(objects_mutex); } @@ -69,14 +71,7 @@ GfxObj::~GfxObj() { // we have to remove this object from the map jmutex_lock(objects_mutex); - { - std::map::iterator - it = objects_map.find(this->id); - - assert(it != objects_map.end()); - - objects_map.erase(it); - } + erase_gfxobj(this); jmutex_unlock(objects_mutex); } @@ -88,7 +83,7 @@ void GfxObj::assign_id() this->id = ++object_id; // 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); } @@ -115,7 +110,29 @@ GfxObj* gfxobj_find(gfxobj_id id) void _gfxobj_set_id(GfxObj* gfxobj, gfxobj_id id) { + assert(gfxobj_find(gfxobj->id) == gfxobj); 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::iterator + it = objects_map.find(gfxobj->id); + + assert(it != objects_map.end()); + + objects_map.erase(it); } diff --git a/src/raster/image.cpp b/src/raster/image.cpp index 36eaa4340..aeffcccf4 100644 --- a/src/raster/image.cpp +++ b/src/raster/image.cpp @@ -545,3 +545,47 @@ int image_count_diff(const Image* i1, const Image* i2) 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 +} + diff --git a/src/raster/image.h b/src/raster/image.h index 866bd495f..07d36f63c 100644 --- a/src/raster/image.h +++ b/src/raster/image.h @@ -138,5 +138,6 @@ void image_to_allegro(Image* image, BITMAP* bmp, int x, int y); void image_convert(Image* dst, const Image* src); 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 */ diff --git a/src/raster/sprite.cpp b/src/raster/sprite.cpp index 56e0ac5b1..fd50bbf4e 100644 --- a/src/raster/sprite.cpp +++ b/src/raster/sprite.cpp @@ -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) { + assert(w > 0); + assert(h > 0); + sprite->w = w; sprite->h = h; } diff --git a/src/raster/stock.cpp b/src/raster/stock.cpp index 17eb660fe..c0dc1dd7c 100644 --- a/src/raster/stock.cpp +++ b/src/raster/stock.cpp @@ -41,8 +41,10 @@ Stock::Stock(const Stock& stock) : GfxObj(stock) { this->imgtype = stock.imgtype; + this->nimage = 0; + this->image = NULL; - for (int c=this->nimage; cnimage; i++) { - if (this->image[i] != NULL) + if (this->image[i]) image_free(this->image[i]); } jfree(this->image); diff --git a/src/raster/undo.cpp b/src/raster/undo.cpp index 4b0ea3b37..4f2a6c5ea 100644 --- a/src/raster/undo.cpp +++ b/src/raster/undo.cpp @@ -627,7 +627,6 @@ static void chunk_image_new(UndoStream* stream, Image* image, int x, int y, int chunk->y = y; chunk->w = w; chunk->h = h; -/* chunk->data = jmalloc(size*h); */ ptr = chunk->data; for (v=0; vdata); */ -/* } */ - static void chunk_image_invert(UndoStream* stream, UndoChunkImage* chunk, int state) { 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) { - Image* image = stock->image[image_index]; + Image* image = stock_get_image(stock, image_index); UndoChunkReplaceImage* chunk = (UndoChunkReplaceImage* ) undo_chunk_new(stream, 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 image_index = chunk->image_index; - Stock *stock = (Stock *)gfxobj_find(stock_id); + Stock* stock = (Stock*)gfxobj_find(stock_id); if (stock) { + // read the image to be restored from the chunk Image* image = read_raw_image(chunk->data); + // save the current image in the (redo) stream chunk_replace_image_new(stream, stock, image_index); + Image* old_image = stock_get_image(stock, image_index); - if (stock->image[image_index]) - image_free(stock->image[image_index]); - + // replace the image in the stock stock_replace_image(stock, image_index, image); + + // destroy the old image + image_free(old_image); } } diff --git a/src/raster/undoable.cpp b/src/raster/undoable.cpp index 46ac9acd0..f7e9363b1 100644 --- a/src/raster/undoable.cpp +++ b/src/raster/undoable.cpp @@ -118,6 +118,69 @@ void Undoable::set_current_layer(Layer* 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->frameframes; 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. * @@ -154,6 +217,22 @@ void Undoable::remove_image_from_stock(int image_index) 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. */ @@ -221,6 +300,47 @@ void Undoable::move_layer_after(Layer* 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(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(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(link->data), dx, dy); + break; + } + + } +} + void Undoable::new_frame() { // add a new cel to every layer @@ -399,6 +519,19 @@ void Undoable::set_cel_frame_position(Cel* cel, int 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) { if (is_enabled()) @@ -509,6 +642,21 @@ Cel* Undoable::get_current_cel() 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) { 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; +} + diff --git a/src/raster/undoable.h b/src/raster/undoable.h index 2f0581d6d..889960f51 100644 --- a/src/raster/undoable.h +++ b/src/raster/undoable.h @@ -47,15 +47,21 @@ public: void set_number_of_frames(int frames); void set_current_frame(int frame); 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 int add_image_in_stock(Image* image); void remove_image_from_stock(int image_index); + void replace_stock_image(int image_index, Image* new_image); // for layers Layer* new_layer(); void remove_layer(Layer* layer); 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 void new_frame(); @@ -72,12 +78,18 @@ public: void add_cel(Layer* layer, Cel* cel); void remove_cel(Layer* layer, Cel* cel); void set_cel_frame_position(Cel* cel, int frame); + void set_cel_position(Cel* cel, int x, int y); Cel* get_current_cel(); + void crop_cel(Cel* cel, int x, int y, int w, int h, int bgcolor); // for image Image* get_cel_image(Cel* cel); 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 */ diff --git a/src/util/autocrop.cpp b/src/util/autocrop.cpp index 32dca1758..b727b491d 100644 --- a/src/util/autocrop.cpp +++ b/src/util/autocrop.cpp @@ -24,56 +24,6 @@ #include "util/autocrop.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->frameframes; 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, Image *image, int refpixel) { diff --git a/src/util/autocrop.h b/src/util/autocrop.h index c1adb63fc..4ae1ef06a 100644 --- a/src/util/autocrop.h +++ b/src/util/autocrop.h @@ -19,8 +19,6 @@ #ifndef UTIL_AUTOCROP_H #define UTIL_AUTOCROP_H -void autocrop_sprite(Sprite *sprite); - bool get_shrink_rect(int *x1, int *y1, int *x2, int *y2, Image *image, int refpixel); bool get_shrink_rect2(int *x1, int *y1, int *x2, int *y2, diff --git a/src/util/functions.cpp b/src/util/functions.cpp index fe40f6185..eab8b6fb9 100644 --- a/src/util/functions.cpp +++ b/src/util/functions.cpp @@ -35,8 +35,6 @@ /* Sprite */ /*===================================================================*/ -static void displace_layers(Undo *undo, Layer *layer, int x, int y); - /** * Creates a new sprite with the given dimension with one transparent * layer called "Layer 1". @@ -142,78 +140,6 @@ void SetSprite(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(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(link->data), x, y); - break; - } - - } -} - /*===================================================================*/ /* Layer */ /*===================================================================*/ @@ -391,41 +317,6 @@ Layer *FlattenLayers(Sprite *sprite) 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(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. */ @@ -667,38 +558,3 @@ void RemoveCel(Layer *layer, Cel *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); - } -} diff --git a/src/util/functions.h b/src/util/functions.h index e09897b6b..eb72df6b8 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -33,8 +33,6 @@ void SaveSprite(const char* filename); void SetSprite(Sprite* sprite); -void CropSprite(Sprite* sprite); - /*===================================================================*/ /* Layer */ /*===================================================================*/ @@ -45,8 +43,6 @@ char *GetUniqueLayerName(Sprite* sprite); Layer* FlattenLayers(Sprite* sprite); -void CropLayer(Layer* layer, int x, int y, int w, int h); - void BackgroundFromLayer(Sprite* sprite); void LayerFromBackground(Sprite* sprite); @@ -56,6 +52,4 @@ void LayerFromBackground(Sprite* sprite); void RemoveCel(Layer* layer, Cel* cel); -void CropCel(); - #endif /* UTIL_FUNCTIONS_H */