mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-02 13:20:12 +00:00
273 lines
8.0 KiB
C++
273 lines
8.0 KiB
C++
/* ASE - Allegro Sprite Editor
|
|
* Copyright (C) 2001-2011 David Capello
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "app.h"
|
|
#include "app/color.h"
|
|
#include "console.h"
|
|
#include "modules/gui.h"
|
|
#include "raster/blend.h"
|
|
#include "raster/cel.h"
|
|
#include "raster/image.h"
|
|
#include "raster/layer.h"
|
|
#include "raster/sprite.h"
|
|
#include "raster/stock.h"
|
|
#include "raster/undo_history.h"
|
|
#include "sprite_wrappers.h"
|
|
#include "util/celmove.h"
|
|
|
|
/* these variables indicate what cel to move (and the sprite's
|
|
frame indicates where to move it) */
|
|
static Layer* src_layer = NULL; // TODO warning not thread safe
|
|
static Layer* dst_layer = NULL;
|
|
static int src_frame = 0;
|
|
static int dst_frame = 0;
|
|
|
|
static void remove_cel(Sprite* sprite, LayerImage* layer, Cel* cel);
|
|
|
|
void set_frame_to_handle(Layer *_src_layer, int _src_frame,
|
|
Layer *_dst_layer, int _dst_frame)
|
|
{
|
|
src_layer = _src_layer;
|
|
src_frame = _src_frame;
|
|
dst_layer = _dst_layer;
|
|
dst_frame = _dst_frame;
|
|
}
|
|
|
|
void move_cel(SpriteWriter& sprite)
|
|
{
|
|
Cel *src_cel, *dst_cel;
|
|
|
|
ASSERT(src_layer != NULL);
|
|
ASSERT(dst_layer != NULL);
|
|
ASSERT(src_frame >= 0 && src_frame < sprite->getTotalFrames());
|
|
ASSERT(dst_frame >= 0 && dst_frame < sprite->getTotalFrames());
|
|
|
|
if (src_layer->is_background()) {
|
|
copy_cel(sprite);
|
|
return;
|
|
}
|
|
|
|
src_cel = static_cast<LayerImage*>(src_layer)->getCel(src_frame);
|
|
dst_cel = static_cast<LayerImage*>(dst_layer)->getCel(dst_frame);
|
|
|
|
if (sprite->getUndo()->isEnabled()) {
|
|
sprite->getUndo()->setLabel("Move Cel");
|
|
sprite->getUndo()->undo_open();
|
|
|
|
sprite->getUndo()->undo_set_layer(sprite);
|
|
sprite->getUndo()->undo_set_frame(sprite);
|
|
}
|
|
|
|
sprite->setCurrentLayer(dst_layer);
|
|
sprite->setCurrentFrame(dst_frame);
|
|
|
|
/* remove the 'dst_cel' (if it exists) because it must be
|
|
replaced with 'src_cel' */
|
|
if ((dst_cel != NULL) && (!dst_layer->is_background() || src_cel != NULL))
|
|
remove_cel(sprite, static_cast<LayerImage*>(dst_layer), dst_cel);
|
|
|
|
/* move the cel in the same layer */
|
|
if (src_cel != NULL) {
|
|
if (src_layer == dst_layer) {
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_int(src_cel, &src_cel->frame);
|
|
|
|
src_cel->frame = dst_frame;
|
|
}
|
|
/* move the cel in different layers */
|
|
else {
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_remove_cel(src_layer, src_cel);
|
|
static_cast<LayerImage*>(src_layer)->removeCel(src_cel);
|
|
|
|
src_cel->frame = dst_frame;
|
|
|
|
/* if we are moving a cel from a transparent layer to the
|
|
background layer, we have to clear the background of the
|
|
image */
|
|
if (!src_layer->is_background() &&
|
|
dst_layer->is_background()) {
|
|
Image *src_image = sprite->getStock()->getImage(src_cel->image);
|
|
Image *dst_image = image_crop(src_image,
|
|
-src_cel->x,
|
|
-src_cel->y,
|
|
sprite->getWidth(),
|
|
sprite->getHeight(), 0);
|
|
|
|
if (sprite->getUndo()->isEnabled()) {
|
|
sprite->getUndo()->undo_replace_image(sprite->getStock(), src_cel->image);
|
|
sprite->getUndo()->undo_int(src_cel, &src_cel->x);
|
|
sprite->getUndo()->undo_int(src_cel, &src_cel->y);
|
|
sprite->getUndo()->undo_int(src_cel, &src_cel->opacity);
|
|
}
|
|
|
|
image_clear(dst_image, app_get_color_to_clear_layer(dst_layer));
|
|
image_merge(dst_image, src_image, src_cel->x, src_cel->y, 255, BLEND_MODE_NORMAL);
|
|
|
|
src_cel->x = 0;
|
|
src_cel->y = 0;
|
|
src_cel->opacity = 255;
|
|
|
|
sprite->getStock()->replaceImage(src_cel->image, dst_image);
|
|
image_free(src_image);
|
|
}
|
|
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_add_cel(dst_layer, src_cel);
|
|
|
|
static_cast<LayerImage*>(dst_layer)->addCel(src_cel);
|
|
}
|
|
}
|
|
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_close();
|
|
|
|
set_frame_to_handle(NULL, 0, NULL, 0);
|
|
}
|
|
|
|
void copy_cel(SpriteWriter& sprite)
|
|
{
|
|
Cel *src_cel, *dst_cel;
|
|
|
|
ASSERT(src_layer != NULL);
|
|
ASSERT(dst_layer != NULL);
|
|
ASSERT(src_frame >= 0 && src_frame < sprite->getTotalFrames());
|
|
ASSERT(dst_frame >= 0 && dst_frame < sprite->getTotalFrames());
|
|
|
|
src_cel = static_cast<LayerImage*>(src_layer)->getCel(src_frame);
|
|
dst_cel = static_cast<LayerImage*>(dst_layer)->getCel(dst_frame);
|
|
|
|
if (sprite->getUndo()->isEnabled()) {
|
|
sprite->getUndo()->setLabel("Move Cel");
|
|
sprite->getUndo()->undo_open();
|
|
|
|
sprite->getUndo()->undo_set_layer(sprite);
|
|
sprite->getUndo()->undo_set_frame(sprite);
|
|
}
|
|
|
|
sprite->setCurrentLayer(dst_layer);
|
|
sprite->setCurrentFrame(dst_frame);
|
|
|
|
/* remove the 'dst_cel' (if it exists) because it must be
|
|
replaced with 'src_cel' */
|
|
if ((dst_cel != NULL) && (!dst_layer->is_background() || src_cel != NULL))
|
|
remove_cel(sprite, static_cast<LayerImage*>(dst_layer), dst_cel);
|
|
|
|
/* move the cel in the same layer */
|
|
if (src_cel != NULL) {
|
|
Image *src_image = sprite->getStock()->getImage(src_cel->image);
|
|
Image *dst_image;
|
|
int image_index;
|
|
int dst_cel_x;
|
|
int dst_cel_y;
|
|
int dst_cel_opacity;
|
|
|
|
/* if we are moving a cel from a transparent layer to the
|
|
background layer, we have to clear the background of the
|
|
image */
|
|
if (!src_layer->is_background() &&
|
|
dst_layer->is_background()) {
|
|
dst_image = image_crop(src_image,
|
|
-src_cel->x,
|
|
-src_cel->y,
|
|
sprite->getWidth(),
|
|
sprite->getHeight(), 0);
|
|
|
|
image_clear(dst_image, app_get_color_to_clear_layer(dst_layer));
|
|
image_merge(dst_image, src_image, src_cel->x, src_cel->y, 255, BLEND_MODE_NORMAL);
|
|
|
|
dst_cel_x = 0;
|
|
dst_cel_y = 0;
|
|
dst_cel_opacity = 255;
|
|
}
|
|
else {
|
|
dst_image = image_new_copy(src_image);
|
|
dst_cel_x = src_cel->x;
|
|
dst_cel_y = src_cel->y;
|
|
dst_cel_opacity = src_cel->opacity;
|
|
}
|
|
|
|
/* add the image in the stock */
|
|
image_index = sprite->getStock()->addImage(dst_image);
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_add_image(sprite->getStock(), image_index);
|
|
|
|
/* create the new cel */
|
|
dst_cel = cel_new(dst_frame, image_index);
|
|
cel_set_position(dst_cel, dst_cel_x, dst_cel_y);
|
|
cel_set_opacity(dst_cel, dst_cel_opacity);
|
|
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_add_cel(dst_layer, dst_cel);
|
|
|
|
static_cast<LayerImage*>(dst_layer)->addCel(dst_cel);
|
|
}
|
|
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_close();
|
|
|
|
set_frame_to_handle(NULL, 0, NULL, 0);
|
|
}
|
|
|
|
static void remove_cel(Sprite* sprite, LayerImage *layer, Cel *cel)
|
|
{
|
|
Image *image;
|
|
Cel *it;
|
|
int frame;
|
|
bool used;
|
|
|
|
if (sprite != NULL && layer->is_image() && cel != NULL) {
|
|
/* find if the image that use the cel to remove, is used by
|
|
another cels */
|
|
used = false;
|
|
for (frame=0; frame<sprite->getTotalFrames(); ++frame) {
|
|
it = layer->getCel(frame);
|
|
if (it != NULL && it != cel && it->image == cel->image) {
|
|
used = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_open();
|
|
|
|
if (!used) {
|
|
/* if the image is only used by this cel, we can remove the
|
|
image from the stock */
|
|
image = sprite->getStock()->getImage(cel->image);
|
|
|
|
if (sprite->getUndo()->isEnabled())
|
|
sprite->getUndo()->undo_remove_image(sprite->getStock(), cel->image);
|
|
|
|
sprite->getStock()->removeImage(image);
|
|
image_free(image);
|
|
}
|
|
|
|
if (sprite->getUndo()->isEnabled()) {
|
|
sprite->getUndo()->undo_remove_cel(layer, cel);
|
|
sprite->getUndo()->undo_close();
|
|
}
|
|
|
|
// Remove the cel
|
|
layer->removeCel(cel);
|
|
cel_free(cel);
|
|
}
|
|
}
|