Replace doc::Stock with doc::ImageRef shared pointer

Changes:
* Add doc::ImageRef to count references to the same image between Cels
  (at this moment we cannot generate linked cels anyway)
* Remove doc:Stock class and doc::Sprite::m_stock member variable
* Remove app::undoers::Add/RemoveImage
* Add doc::SubObjectsIO and app::undoers::ObjectIO to
  replace doc::LayerSubObjectsSerializer
This commit is contained in:
David Capello 2015-01-04 10:58:14 -03:00
parent 1b55fe39dc
commit f1f24cbcdd
61 changed files with 510 additions and 949 deletions

View File

@ -265,7 +265,6 @@ add_library(app-lib
undo_transaction.cpp
undoers/add_cel.cpp
undoers/add_frame.cpp
undoers/add_image.cpp
undoers/add_layer.cpp
undoers/add_palette.cpp
undoers/close_group.cpp
@ -274,11 +273,11 @@ add_library(app-lib
undoers/image_area.cpp
undoers/modified_region.cpp
undoers/move_layer.cpp
undoers/object_io.cpp
undoers/open_group.cpp
undoers/remap_palette.cpp
undoers/remove_cel.cpp
undoers/remove_frame.cpp
undoers/remove_image.cpp
undoers/remove_layer.cpp
undoers/remove_palette.cpp
undoers/replace_image.cpp

View File

@ -33,7 +33,6 @@
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
namespace app {

View File

@ -45,7 +45,6 @@
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
#include "generated_export_sprite_sheet.h"
@ -327,7 +326,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
if (sheet_h == 0) sheet_h = sprite->height()*((nframes/columns)+((nframes%columns)>0?1:0));
columns = sheet_w / sprite->width();
base::UniquePtr<Image> resultImage(Image::create(sprite->pixelFormat(), sheet_w, sheet_h));
ImageRef resultImage(Image::create(sprite->pixelFormat(), sheet_w, sheet_h));
doc::clear_image(resultImage, 0);
render::Render render;
@ -360,12 +359,8 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
// Add the layer in the sprite.
LayerImage* resultLayer = api.newLayer(sprite);
// Add the image into the sprite's stock
int indexInStock = api.addImageInStock(sprite, resultImage);
resultImage.release();
// Create the cel.
base::UniquePtr<Cel> resultCel(new Cel(frame_t(0), indexInStock));
base::UniquePtr<Cel> resultCel(new Cel(frame_t(0), resultImage));
// Add the cel in the layer.
api.addCel(resultLayer, resultCel);

View File

@ -39,7 +39,6 @@
#include "doc/layer.h"
#include "doc/mask.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace app {

View File

@ -45,7 +45,6 @@
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
namespace app {
@ -160,7 +159,7 @@ protected:
}
// The list of frames imported from the sheet
std::vector<Image*> animation;
std::vector<ImageRef> animation;
try {
Sprite* sprite = m_document->sprite();
@ -170,7 +169,7 @@ protected:
// As first step, we cut each tile and add them into "animation" list.
for (int y=m_rect.y; y<sprite->height(); y += m_rect.h) {
for (int x=m_rect.x; x<sprite->width(); x += m_rect.w) {
base::UniquePtr<Image> resultImage(
ImageRef resultImage(
Image::create(sprite->pixelFormat(), m_rect.w, m_rect.h));
// Render the portion of sheet.
@ -178,7 +177,6 @@ protected:
gfx::Clip(0, 0, x, y, m_rect.w, m_rect.h));
animation.push_back(resultImage);
resultImage.release();
}
}
@ -201,14 +199,8 @@ protected:
// Add all frames+cels to the new layer
for (size_t i=0; i<animation.size(); ++i) {
int indexInStock;
// Add the image into the sprite's stock
indexInStock = api.addImageInStock(sprite, animation[i]);
animation[i] = NULL;
// Create the cel.
base::UniquePtr<Cel> resultCel(new Cel(frame_t(i), indexInStock));
base::UniquePtr<Cel> resultCel(new Cel(frame_t(i), animation[i]));
// Add the cel in the layer.
api.addCel(resultLayer, resultCel);
@ -233,8 +225,6 @@ protected:
undoTransaction.commit();
}
catch (...) {
for (size_t i=0; i<animation.size(); ++i)
delete animation[i];
throw;
}

View File

@ -28,7 +28,6 @@
#include "app/modules/gui.h"
#include "app/undo_transaction.h"
#include "app/undoers/add_cel.h"
#include "app/undoers/add_image.h"
#include "app/undoers/remove_layer.h"
#include "app/undoers/replace_image.h"
#include "app/undoers/set_cel_position.h"
@ -38,7 +37,6 @@
#include "doc/layer.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "render/render.h"
#include "ui/ui.h"
@ -87,7 +85,6 @@ void MergeDownLayerCommand::onExecute(Context* context)
UndoTransaction undo(writer.context(), "Merge Down Layer", undo::ModifyDocument);
Layer* src_layer = writer.layer();
Layer* dst_layer = src_layer->getPrevious();
int index;
for (frame_t frpos = 0; frpos<sprite->totalFrames(); ++frpos) {
// Get frames
@ -101,29 +98,21 @@ void MergeDownLayerCommand::onExecute(Context* context)
else
src_image = NULL;
Image* dst_image;
if (dst_cel != NULL)
dst_image = dst_cel->image();
else
dst_image = NULL;
ImageRef dst_image;
if (dst_cel)
dst_image = dst_cel->imageRef();
// With source image?
if (src_image != NULL) {
if (src_image) {
// No destination image
if (dst_image == NULL) { // Only a transparent layer can have a null cel
// Copy this cel to the destination layer...
// Creating a copy of the image
dst_image = Image::createCopy(src_image);
// Adding it in the stock of images
index = sprite->stock()->addImage(dst_image);
if (undo.isEnabled())
undo.pushUndoer(new undoers::AddImage(
undo.getObjects(), sprite->stock(), index));
dst_image.reset(Image::createCopy(src_image));
// Creating a copy of the cell
dst_cel = new Cel(frpos, index);
dst_cel = new Cel(frpos, dst_image);
dst_cel->setPosition(src_cel->x(), src_cel->y());
dst_cel->setOpacity(src_cel->opacity());
@ -153,10 +142,10 @@ void MergeDownLayerCommand::onExecute(Context* context)
doc::color_t bgcolor = app_get_color_to_clear_layer(dst_layer);
Image* new_image = doc::crop_image(dst_image,
x1-dst_cel->x(),
y1-dst_cel->y(),
x2-x1+1, y2-y1+1, bgcolor);
ImageRef new_image(doc::crop_image(dst_image,
x1-dst_cel->x(),
y1-dst_cel->y(),
x2-x1+1, y2-y1+1, bgcolor));
// Merge src_image in new_image
render::composite_image(new_image, src_image,
@ -172,10 +161,9 @@ void MergeDownLayerCommand::onExecute(Context* context)
if (undo.isEnabled())
undo.pushUndoer(new undoers::ReplaceImage(undo.getObjects(),
sprite->stock(), dst_cel->imageIndex()));
sprite, dst_cel->image(), new_image));
sprite->stock()->replaceImage(dst_cel->imageIndex(), new_image);
delete dst_image;
sprite->replaceImage(dst_cel->image()->id(), new_image);
}
}
}

View File

@ -42,7 +42,6 @@
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
#include "generated_new_sprite.h"

View File

@ -52,7 +52,6 @@
#include "doc/image.h"
#include "doc/palette.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include "gfx/size.h"

View File

@ -38,7 +38,6 @@
#include "doc/image.h"
#include "doc/mask.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
namespace app {
@ -116,12 +115,12 @@ protected:
}
// rotate the image
Image* new_image = Image::create(image->pixelFormat(),
m_angle == 180 ? image->width(): image->height(),
m_angle == 180 ? image->height(): image->width());
ImageRef new_image(Image::create(image->pixelFormat(),
m_angle == 180 ? image->width(): image->height(),
m_angle == 180 ? image->height(): image->width()));
doc::rotate_image(image, new_image, m_angle);
api.replaceStockImage(m_sprite, cel->imageIndex(), new_image);
api.replaceImage(m_sprite, cel->imageRef(), new_image);
}
jobProgress((float)i / m_cels.size());

View File

@ -41,7 +41,6 @@
#include "doc/mask.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
#define PERC_FORMAT "%.1f"
@ -105,15 +104,15 @@ protected:
// Resize the image
int w = scale_x(image->width());
int h = scale_y(image->height());
Image* new_image = Image::create(image->pixelFormat(), MAX(1, w), MAX(1, h));
ImageRef new_image(Image::create(image->pixelFormat(), MAX(1, w), MAX(1, h)));
doc::algorithm::fixup_image_transparent_colors(image);
doc::algorithm::resize_image(image, new_image,
m_resize_method,
m_sprite->palette(cel->frame()),
m_sprite->rgbMap(cel->frame()));
m_resize_method,
m_sprite->palette(cel->frame()),
m_sprite->rgbMap(cel->frame()));
api.replaceStockImage(m_sprite, cel->imageIndex(), new_image);
api.replaceImage(m_sprite, cel->imageRef(), new_image);
jobProgress((float)progress / cels.size());
@ -124,7 +123,7 @@ protected:
// Resize mask
if (m_document->isMaskVisible()) {
base::UniquePtr<Image> old_bitmap
ImageRef old_bitmap
(crop_image(m_document->mask()->bitmap(), -1, -1,
m_document->mask()->bitmap()->width()+2,
m_document->mask()->bitmap()->height()+2, 0));
@ -137,9 +136,9 @@ protected:
scale_x(m_document->mask()->bounds().x-1),
scale_y(m_document->mask()->bounds().y-1), MAX(1, w), MAX(1, h)));
algorithm::resize_image(old_bitmap, new_mask->bitmap(),
m_resize_method,
m_sprite->palette(0), // Ignored
m_sprite->rgbMap(0)); // Ignored
m_resize_method,
m_sprite->palette(0), // Ignored
m_sprite->rgbMap(0)); // Ignored
// Reshrink
new_mask->intersect(new_mask->bounds());

View File

@ -35,7 +35,6 @@
#include "doc/layer.h"
#include "doc/mask.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/manager.h"
#include "ui/view.h"
#include "ui/widget.h"

View File

@ -28,7 +28,6 @@
#include "doc/cel.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace app {

View File

@ -27,7 +27,6 @@
#include "app/file/format_options.h"
#include "app/flatten.h"
#include "app/objects_container_impl.h"
#include "app/undoers/add_image.h"
#include "app/undoers/add_layer.h"
#include "app/util/boundary.h"
#include "base/memory.h"
@ -41,7 +40,6 @@
#include "doc/mask.h"
#include "doc/palette.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace app {
@ -235,10 +233,9 @@ void Document::generateMaskBoundaries(Mask* mask)
void Document::destroyExtraCel()
{
delete m_extraCel;
delete m_extraImage;
m_extraCel = NULL;
m_extraImage = NULL;
m_extraImage.reset(NULL);
}
void Document::prepareExtraCel(const gfx::Rect& bounds, int opacity)
@ -246,7 +243,7 @@ void Document::prepareExtraCel(const gfx::Rect& bounds, int opacity)
ASSERT(sprite() != NULL);
if (!m_extraCel)
m_extraCel = new Cel(frame_t(0), 0); // Ignored fields for this cell (frame, and image index)
m_extraCel = new Cel(frame_t(0), ImageRef(NULL)); // Ignored fields for this cel (frame, and image index)
m_extraCel->setPosition(bounds.getOrigin());
m_extraCel->setOpacity(opacity);
@ -255,9 +252,8 @@ void Document::prepareExtraCel(const gfx::Rect& bounds, int opacity)
m_extraImage->pixelFormat() != sprite()->pixelFormat() ||
m_extraImage->width() != bounds.w ||
m_extraImage->height() != bounds.h) {
delete m_extraImage; // image
m_extraImage = Image::create(sprite()->pixelFormat(),
bounds.w, bounds.h);
m_extraImage.reset(Image::create(sprite()->pixelFormat(),
bounds.w, bounds.h));
}
}
@ -268,7 +264,7 @@ Cel* Document::getExtraCel() const
Image* Document::getExtraCelImage() const
{
return m_extraImage;
return m_extraImage.get();
}
//////////////////////////////////////////////////////////////////////
@ -342,8 +338,8 @@ void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, La
const Image* sourceImage = sourceCel->image();
ASSERT(sourceImage != NULL);
Image* newImage = Image::createCopy(sourceImage);
newCel->setImage(destLayer->sprite()->stock()->addImage(newImage));
ImageRef newImage(Image::createCopy(sourceImage));
newCel->setImage(newImage);
destLayer->addCel(newCel);
newCel.release();

View File

@ -27,6 +27,7 @@
#include "base/unique_ptr.h"
#include "doc/document.h"
#include "doc/frame.h"
#include "doc/image_ref.h"
#include "doc/pixel_format.h"
#include "gfx/rect.h"
#include "gfx/transformation.h"
@ -39,7 +40,6 @@ namespace base {
namespace doc {
class Cel;
class Image;
class Layer;
class Mask;
class Sprite;
@ -219,7 +219,7 @@ namespace app {
Cel* m_extraCel;
// Image of the extra cel.
Image* m_extraImage;
ImageRef m_extraImage;
int m_extraCelBlendMode;
// Current mask.

View File

@ -29,7 +29,6 @@
#include "app/settings/settings.h"
#include "app/undoers/add_cel.h"
#include "app/undoers/add_frame.h"
#include "app/undoers/add_image.h"
#include "app/undoers/add_layer.h"
#include "app/undoers/add_palette.h"
#include "app/undoers/dirty_area.h"
@ -39,7 +38,6 @@
#include "app/undoers/move_layer.h"
#include "app/undoers/remove_cel.h"
#include "app/undoers/remove_frame.h"
#include "app/undoers/remove_image.h"
#include "app/undoers/remove_layer.h"
#include "app/undoers/remove_palette.h"
#include "app/undoers/replace_image.h"
@ -73,7 +71,6 @@
#include "doc/mask.h"
#include "doc/palette.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "render/quantization.h"
#include "render/render.h"
@ -157,10 +154,6 @@ void DocumentApi::trimSprite(Sprite* sprite)
void DocumentApi::setPixelFormat(Sprite* sprite, PixelFormat newFormat, DitheringMethod dithering_method)
{
Image* old_image;
Image* new_image;
int c;
if (sprite->pixelFormat() == newFormat)
return;
@ -177,25 +170,23 @@ void DocumentApi::setPixelFormat(Sprite* sprite, PixelFormat newFormat, Ditherin
if (sprite->backgroundLayer() != NULL)
sprite->backgroundLayer()->getCels(bgCels);
for (c=0; c<sprite->stock()->size(); c++) {
old_image = sprite->stock()->getImage(c);
if (!old_image)
continue;
std::vector<Image*> images;
sprite->getImages(images);
for (auto& old_image : images) {
bool is_image_from_background = false;
for (CelList::iterator it=bgCels.begin(), end=bgCels.end(); it != end; ++it) {
if ((*it)->imageIndex() == c) {
if ((*it)->image()->id() == old_image->id()) {
is_image_from_background = true;
break;
}
}
new_image = render::convert_pixel_format
ImageRef new_image(render::convert_pixel_format
(old_image, NULL, newFormat, dithering_method, rgbmap,
sprite->palette(frame),
is_image_from_background);
sprite->palette(frame),
is_image_from_background));
replaceStockImage(sprite, c, new_image);
replaceImage(sprite, sprite->getImage(old_image->id()), new_image);
}
// Set all cels opacity to 100% if we are converting to indexed.
@ -310,9 +301,9 @@ void DocumentApi::displaceFrames(Layer* layer, frame_t frame)
// Add background cel
if (imglayer->isBackground()) {
Image* bgimage = Image::create(sprite->pixelFormat(), sprite->width(), sprite->height());
ImageRef bgimage(Image::create(sprite->pixelFormat(), sprite->width(), sprite->height()));
clear_image(bgimage, bgColor(layer));
addImage(imglayer, frame, bgimage);
addCel(imglayer, frame, bgimage);
}
break;
}
@ -583,18 +574,8 @@ void DocumentApi::removeCel(Cel* cel)
ev.cel(cel);
m_document->notifyObservers<doc::DocumentEvent&>(&doc::DocumentObserver::onRemoveCel, ev);
// Find if the image that use this cel we are going to remove, is
// used by other cels.
size_t refs = sprite->getImageRefs(cel->imageIndex());
// If the image is only used by this cel, we can remove the image
// from the stock.
if (refs == 1)
removeImageFromStock(sprite, cel->imageIndex());
if (undoEnabled())
m_undoers->pushUndoer(new undoers::RemoveCel(getObjects(),
layer, cel));
m_undoers->pushUndoer(new undoers::RemoveCel(getObjects(), layer, cel));
// Remove the cel from the layer.
layer->removeCel(cel);
@ -658,11 +639,11 @@ void DocumentApi::cropCel(Sprite* sprite, Cel* cel, int x, int y, int w, int h)
ASSERT(cel_image);
// create the new image through a crop
Image* new_image = crop_image(cel_image,
x-cel->x(), y-cel->y(), w, h, bgColor(cel->layer()));
ImageRef new_image(crop_image(cel_image,
x-cel->x(), y-cel->y(), w, h, bgColor(cel->layer())));
// replace the image in the stock that is pointed by the cel
replaceStockImage(sprite, cel->imageIndex(), new_image);
replaceImage(sprite, cel->imageRef(), new_image);
// update the cel's position
setCelPosition(sprite, cel, x, y);
@ -714,7 +695,9 @@ void DocumentApi::moveCel(
Cel* srcCel = srcLayer->cel(srcFrame);
Cel* dstCel = dstLayer->cel(dstFrame);
Image* srcImage = (srcCel ? srcCel->image(): NULL);
Image* dstImage = (dstCel ? dstCel->image(): NULL);
ImageRef dstImage;
if (dstCel)
dstImage = dstCel->imageRef();
if (srcCel) {
if (srcLayer == dstLayer) {
@ -738,11 +721,11 @@ void DocumentApi::moveCel(
// Move the cel between different layers.
else {
if (!dstCel) {
dstImage = Image::createCopy(srcImage);
dstImage.reset(Image::createCopy(srcImage));
dstCel = new Cel(*srcCel);
dstCel->setFrame(dstFrame);
dstCel->setImage(addImageInStock(dstSprite, dstImage));
dstCel->setImage(dstImage);
}
if (dstLayer->isBackground()) {
@ -781,7 +764,9 @@ void DocumentApi::copyCel(
Cel* srcCel = srcLayer->cel(srcFrame);
Cel* dstCel = dstLayer->cel(dstFrame);
Image* srcImage = (srcCel ? srcCel->image(): NULL);
Image* dstImage = (dstCel ? dstCel->image(): NULL);
ImageRef dstImage;
if (dstCel)
dstImage = dstCel->imageRef();
if (dstLayer->isBackground()) {
if (srcCel) {
@ -800,13 +785,12 @@ void DocumentApi::copyCel(
removeCel(dstCel);
if (srcCel) {
// Add the image in the stock
dstImage = Image::createCopy(srcImage);
int imageIndex = addImageInStock(dstSprite, dstImage);
// Create a new image in the stock
dstImage.reset(Image::createCopy(srcImage));
dstCel = new Cel(*srcCel);
dstCel->setFrame(dstFrame);
dstCel->setImage(imageIndex);
dstCel->setImage(dstImage);
addCel(dstLayer, dstCel);
}
@ -978,10 +962,9 @@ void DocumentApi::backgroundFromLayer(LayerImage* layer)
// create a temporary image to draw each frame of the new
// `Background' layer
base::UniquePtr<Image> bg_image_wrap(Image::create(sprite->pixelFormat(),
sprite->width(),
sprite->height()));
Image* bg_image = bg_image_wrap.get();
ImageRef bg_image(Image::create(sprite->pixelFormat(),
sprite->width(),
sprite->height()));
CelIterator it = layer->getCelBegin();
CelIterator end = layer->getCelEnd();
@ -1012,7 +995,8 @@ void DocumentApi::backgroundFromLayer(LayerImage* layer)
copy_image(cel_image, bg_image, 0, 0);
}
else {
replaceStockImage(sprite, cel->imageIndex(), Image::createCopy(bg_image));
ImageRef bg_image2(Image::createCopy(bg_image));
replaceImage(sprite, cel->imageRef(), bg_image2);
}
}
@ -1020,14 +1004,12 @@ void DocumentApi::backgroundFromLayer(LayerImage* layer)
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
Cel* cel = layer->cel(frame);
if (!cel) {
Image* cel_image = Image::create(sprite->pixelFormat(), sprite->width(), sprite->height());
ImageRef cel_image(Image::create(sprite->pixelFormat(),
sprite->width(), sprite->height()));
clear_image(cel_image, bgcolor);
// Add the new image in the stock
int image_index = addImageInStock(sprite, cel_image);
// Create the new cel and add it to the new background layer
cel = new Cel(frame, image_index);
cel = new Cel(frame, cel_image);
addCel(layer, cel);
}
}
@ -1057,7 +1039,7 @@ void DocumentApi::layerFromBackground(Layer* layer)
void DocumentApi::flattenLayers(Sprite* sprite)
{
Image* cel_image;
ImageRef cel_image;
Cel* cel;
// Create a temporary image.
@ -1088,7 +1070,7 @@ void DocumentApi::flattenLayers(Sprite* sprite)
cel = background->cel(frame);
if (cel) {
cel_image = cel->image();
cel_image = cel->imageRef();
ASSERT(cel_image != NULL);
// We have to save the current state of `cel_image' in the undo.
@ -1102,11 +1084,11 @@ void DocumentApi::flattenLayers(Sprite* sprite)
else {
// If there aren't a cel in this frame in the background, we
// have to create a copy of the image for the new cel.
cel_image = Image::createCopy(image);
cel_image.reset(Image::createCopy(image));
// TODO error handling: if createCopy throws
// Here we create the new cel (with the new image `cel_image').
cel = new Cel(frame, sprite->stock()->addImage(cel_image));
cel = new Cel(frame, cel_image);
// TODO error handling: if new Cel throws
// And finally we add the cel in the background.
@ -1147,30 +1129,11 @@ void DocumentApi::duplicateLayerBefore(Layer* sourceLayer, Layer* beforeLayer)
duplicateLayerAfter(sourceLayer, sourceLayer->sprite()->indexToLayer(afterThisIdx));
}
// Adds a new image in the stock. Returns the image index in the
// stock.
int DocumentApi::addImageInStock(Sprite* sprite, Image* image)
Cel* DocumentApi::addCel(LayerImage* layer, frame_t frameNumber, const ImageRef& image)
{
ASSERT(image != NULL);
// Do the action.
int imageIndex = sprite->stock()->addImage(image);
// Add undoers.
if (undoEnabled())
m_undoers->pushUndoer(new undoers::AddImage(getObjects(),
sprite->stock(), imageIndex));
return imageIndex;
}
Cel* DocumentApi::addImage(LayerImage* layer, frame_t frameNumber, Image* image)
{
int imageIndex = addImageInStock(layer->sprite(), image);
ASSERT(layer->cel(frameNumber) == NULL);
base::UniquePtr<Cel> cel(new Cel(frameNumber, imageIndex));
base::UniquePtr<Cel> cel(new Cel(frameNumber, image));
addCel(layer, cel);
cel.release();
@ -1178,35 +1141,13 @@ Cel* DocumentApi::addImage(LayerImage* layer, frame_t frameNumber, Image* image)
return cel;
}
// Removes and destroys the specified image in the stock.
void DocumentApi::removeImageFromStock(Sprite* sprite, int imageIndex)
void DocumentApi::replaceImage(Sprite* sprite, const ImageRef& oldImage, const ImageRef& newImage)
{
ASSERT(imageIndex >= 0);
Image* image = sprite->stock()->getImage(imageIndex);
ASSERT(image);
if (undoEnabled())
m_undoers->pushUndoer(new undoers::RemoveImage(getObjects(),
sprite->stock(), imageIndex));
sprite->stock()->removeImage(image);
delete image;
}
void DocumentApi::replaceStockImage(Sprite* sprite, int imageIndex, Image* newImage)
{
// Get the current image in the 'image_index' position.
Image* oldImage = sprite->stock()->getImage(imageIndex);
ASSERT(oldImage);
// Replace the image in the stock.
if (undoEnabled())
m_undoers->pushUndoer(new undoers::ReplaceImage(getObjects(),
sprite->stock(), imageIndex));
sprite, oldImage, newImage));
sprite->stock()->replaceImage(imageIndex, newImage);
delete oldImage;
sprite->replaceImage(oldImage->id(), newImage);
}
void DocumentApi::clearImage(Image* image, color_t bgcolor)

View File

@ -20,12 +20,13 @@
#define APP_DOCUMENT_API_H_INCLUDED
#pragma once
#include "gfx/rect.h"
#include "doc/algorithm/flip_type.h"
#include "doc/color.h"
#include "doc/dithering_method.h"
#include "doc/frame.h"
#include "doc/image_ref.h"
#include "doc/pixel_format.h"
#include "gfx/rect.h"
namespace doc {
class Cel;
@ -79,6 +80,7 @@ namespace app {
// Cels API
void addCel(LayerImage* layer, Cel* cel);
Cel* addCel(LayerImage* layer, frame_t frameNumber, const ImageRef& image);
void clearCel(LayerImage* layer, frame_t frame);
void clearCel(Cel* cel);
void setCelPosition(Sprite* sprite, Cel* cel, int x, int y);
@ -108,11 +110,8 @@ namespace app {
void duplicateLayerAfter(Layer* sourceLayer, Layer* afterLayer);
void duplicateLayerBefore(Layer* sourceLayer, Layer* beforeLayer);
// Images stock API
Cel* addImage(LayerImage* layer, frame_t frameNumber, Image* image);
int addImageInStock(Sprite* sprite, Image* image);
void removeImageFromStock(Sprite* sprite, int imageIndex);
void replaceStockImage(Sprite* sprite, int imageIndex, Image* newImage);
// Images API
void replaceImage(Sprite* sprite, const ImageRef& oldImage, const ImageRef& newImage);
// Image API
void clearImage(Image* image, color_t bgcolor);

View File

@ -38,7 +38,6 @@
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "gfx/packing_rects.h"
#include "gfx/size.h"
#include "render/render.h"

View File

@ -25,7 +25,6 @@
#include "doc/cel.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace app {

View File

@ -118,13 +118,12 @@ public:
for (int j=0; j<4; j++) {
Cel* cel = layer->cel(frame_t(j));
Image* image;
ImageRef image;
if (cel)
image = cel->image();
image = cel->imageRef();
else {
image = Image::create(IMAGE_RGB, 4, 4);
int imageIdx = sprite->stock()->addImage(image);
cel = new Cel(frame_t(j), imageIdx);
image.reset(Image::create(IMAGE_RGB, 4, 4));
cel = new Cel(frame_t(j), image);
layer->addCel(cel);
}

View File

@ -1020,7 +1020,7 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
}
// Create the new frame.
base::UniquePtr<Cel> cel(new Cel(frame, 0));
base::UniquePtr<Cel> cel(new Cel(frame, ImageRef(NULL)));
cel->setPosition(x, y);
cel->setOpacity(opacity);
@ -1032,7 +1032,7 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
int h = fgetw(f);
if (w > 0 && h > 0) {
Image* image = Image::create(pixelFormat, w, h);
ImageRef image(Image::create(pixelFormat, w, h));
// Read pixel data
switch (image->pixelFormat()) {
@ -1050,7 +1050,7 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
break;
}
cel->setImage(sprite->stock()->addImage(image));
cel->setImage(image);
}
break;
}
@ -1061,9 +1061,12 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
Cel* link = layer->cel(link_frame);
if (link) {
// Create a copy of the linked cel (avoid using links cel)
Image* image = Image::createCopy(link->image());
cel->setImage(sprite->stock()->addImage(image));
#if 1 // Create a copy of the linked cel (avoid using links cel)
ImageRef image(Image::createCopy(link->image()));
cel->setImage(image);
#else
cel->setImage(link->imageRef());
#endif
}
else {
// Linked cel doesn't found
@ -1078,7 +1081,7 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
int h = fgetw(f);
if (w > 0 && h > 0) {
Image* image = Image::create(pixelFormat, w, h);
ImageRef image(Image::create(pixelFormat, w, h));
// Try to read pixel data
try {
@ -1103,7 +1106,7 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
fop_error(fop, e.what());
}
cel->setImage(sprite->stock()->addImage(image));
cel->setImage(image);
}
break;
}
@ -1120,7 +1123,8 @@ static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, Cel
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_CEL);
int layer_index = sprite->layerToIndex(layer);
int cel_type = ASE_FILE_COMPRESSED_CEL;
Cel* link = cel->link();
int cel_type = (link ? ASE_FILE_LINK_CEL: ASE_FILE_COMPRESSED_CEL);
fputw(layer_index, f);
fputw(cel->x(), f);
@ -1165,8 +1169,7 @@ static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, Cel
case ASE_FILE_LINK_CEL:
// Linked cel to another frame
//fputw(link->frame, f);
fputw(0, f);
fputw(link->frame(), f);
break;
case ASE_FILE_COMPRESSED_CEL: {

View File

@ -422,7 +422,6 @@ void fop_operate(FileOp *fop, IFileOpProgress* progress)
fop->format->support(FILE_SUPPORT_LOAD)) {
// Load a sequence
if (fop->is_sequence()) {
int image_index = 0;
Image* old_image;
bool loadres;
@ -432,11 +431,7 @@ void fop_operate(FileOp *fop, IFileOpProgress* progress)
// TODO set_palette for each frame???
#define SEQUENCE_IMAGE() \
do { \
image_index = fop->document \
->sprite() \
->stock()->addImage(fop->seq.image); \
\
fop->seq.last_cel->setImage(image_index); \
fop->seq.last_cel->setImage(fop->seq.image); \
fop->seq.layer->addCel(fop->seq.last_cel); \
\
if (fop->document->sprite()->palette(frame) \
@ -446,11 +441,11 @@ void fop_operate(FileOp *fop, IFileOpProgress* progress)
} \
\
old_image = fop->seq.image; \
fop->seq.image = NULL; \
fop->seq.image.reset(NULL); \
fop->seq.last_cel = NULL; \
} while (0)
/* load the sequence */
// Load the sequence
frame_t frames(fop->seq.filename_list.size());
frame_t frame(0);
old_image = NULL;
@ -556,42 +551,38 @@ void fop_operate(FileOp *fop, IFileOpProgress* progress)
Sprite* sprite = fop->document->sprite();
// Create a temporary bitmap
fop->seq.image = Image::create(sprite->pixelFormat(),
sprite->width(),
sprite->height());
if (fop->seq.image != NULL) {
fop->seq.progress_offset = 0.0f;
fop->seq.progress_fraction = 1.0f / (double)sprite->totalFrames();
fop->seq.image.reset(Image::create(sprite->pixelFormat(),
sprite->width(),
sprite->height()));
// For each frame in the sprite.
render::Render render;
for (frame_t frame(0); frame < sprite->totalFrames(); ++frame) {
// Draw the "frame" in "fop->seq.image"
render.renderSprite(fop->seq.image, sprite, frame);
fop->seq.progress_offset = 0.0f;
fop->seq.progress_fraction = 1.0f / (double)sprite->totalFrames();
// Setup the palette.
sprite->palette(frame)->copyColorsTo(fop->seq.palette);
// For each frame in the sprite.
render::Render render;
for (frame_t frame(0); frame < sprite->totalFrames(); ++frame) {
// Draw the "frame" in "fop->seq.image"
render.renderSprite(fop->seq.image, sprite, frame);
// Setup the filename to be used.
fop->filename = fop->seq.filename_list[frame];
// Setup the palette.
sprite->palette(frame)->copyColorsTo(fop->seq.palette);
// Call the "save" procedure... did it fail?
if (!fop->format->save(fop)) {
fop_error(fop, "Error saving frame %d in the file \"%s\"\n",
frame+1, fop->filename.c_str());
break;
}
// Setup the filename to be used.
fop->filename = fop->seq.filename_list[frame];
fop->seq.progress_offset += fop->seq.progress_fraction;
// Call the "save" procedure... did it fail?
if (!fop->format->save(fop)) {
fop_error(fop, "Error saving frame %d in the file \"%s\"\n",
frame+1, fop->filename.c_str());
break;
}
fop->filename = *fop->seq.filename_list.begin();
// Destroy the image
delete fop->seq.image;
}
else {
fop_error(fop, "Not enough memory for the temporary bitmap.\n");
fop->seq.progress_offset += fop->seq.progress_fraction;
}
fop->filename = *fop->seq.filename_list.begin();
// Destroy the image
fop->seq.image.reset(NULL);
}
// Direct save to a file.
else {
@ -741,12 +732,10 @@ Image* fop_sequence_image(FileOp* fop, PixelFormat pixelFormat, int w, int h)
}
// Create a bitmap
Image* image = Image::create(pixelFormat, w, h);
fop->seq.image.reset(Image::create(pixelFormat, w, h));
fop->seq.last_cel = new Cel(fop->seq.frame++, ImageRef(NULL));
fop->seq.image = image;
fop->seq.last_cel = new Cel(fop->seq.frame++, 0);
return image;
return fop->seq.image.get();
}
void fop_error(FileOp *fop, const char *format, ...)
@ -831,7 +820,7 @@ static FileOp* fop_new(FileOpType type, Context* context)
fop->oneframe = false;
fop->seq.palette = NULL;
fop->seq.image = NULL;
fop->seq.image.reset(NULL);
fop->seq.progress_offset = 0.0f;
fop->seq.progress_fraction = 0.0f;
fop->seq.frame = frame_t(0);

View File

@ -22,6 +22,7 @@
#include "base/shared_ptr.h"
#include "doc/frame.h"
#include "doc/image_ref.h"
#include "doc/pixel_format.h"
#include <stdio.h>
@ -95,7 +96,7 @@ namespace app {
struct {
std::vector<std::string> filename_list; // All file names to load/save.
Palette* palette; // Palette of the sequence.
Image* image; // Image to be saved/loaded.
ImageRef image; // Image to be saved/loaded.
// For the progress bar.
double progress_offset; // Progress offset from the current frame.
double progress_fraction; // Progress fraction for one frame.

View File

@ -133,10 +133,8 @@ bool FliFormat::onLoad(FileOp* fop)
++frpos_out;
// Add the new frame
Image* image = Image::createCopy(bmp);
index = sprite->stock()->addImage(image);
Cel* cel = new Cel(frpos_out, index);
ImageRef image(Image::createCopy(bmp));
Cel* cel = new Cel(frpos_out, image);
layer->addCel(cel);
// First frame or the palette changes

View File

@ -456,16 +456,15 @@ bool GifFormat::onPostLoad(FileOp* fop)
}
// Create a new Cel and a image with the whole content of "current_image"
Cel* cel = new Cel(frame_num, 0);
Cel* cel = new Cel(frame_num, ImageRef(0));
try {
Image* cel_image = Image::createCopy(current_image);
ImageRef cel_image(Image::createCopy(current_image));
try {
// Add the image in the sprite's stock and update the cel's
// reference to the new stock's image.
cel->setImage(sprite->stock()->addImage(cel_image));
cel->setImage(cel_image);
}
catch (...) {
delete cel_image;
throw;
}

View File

@ -299,10 +299,9 @@ TEST_F(GifFormat, OpaqueRgbQuantizationTwoLayers)
LayerImage* layer2 = new LayerImage(sprite);
sprite->folder()->addLayer(layer2);
Image* image1 = layer1->cel(frame_t(0))->image();
Image* image2 = Image::create(IMAGE_RGB, 2, 2);
int image2Idx = sprite->stock()->addImage(image2);
Cel* cel2 = new Cel(frame_t(0), image2Idx);
ImageRef image1 = layer1->cel(frame_t(0))->imageRef();
ImageRef image2(Image::create(IMAGE_RGB, 2, 2));
Cel* cel2 = new Cel(frame_t(0), image2);
layer2->addCel(cel2);
image1->clear(rgba(255, 255, 255, 255));

View File

@ -140,9 +140,8 @@ bool IcoFormat::onLoad(FileOp* fop)
sprite->folder()->addLayer(layer);
// Create the first image/cel
Image* image = Image::create(pixelFormat, width, height);
int image_index = sprite->stock()->addImage(image);
Cel* cel = new Cel(frame_t(0), image_index);
ImageRef image(Image::create(pixelFormat, width, height));
Cel* cel = new Cel(frame_t(0), image);
layer->addCel(cel);
clear_image(image, 0);

View File

@ -26,7 +26,6 @@
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "gfx/rect.h"
#include "render/render.h"
@ -47,14 +46,10 @@ LayerImage* create_flatten_layer_copy(Sprite* dstSprite, const Layer* srcLayer,
// Does this frame have cels to render?
if (has_cels(srcLayer, frame)) {
// Create a new image to render each frame.
base::UniquePtr<Image> imageWrap(Image::create(flatLayer->sprite()->pixelFormat(), bounds.w, bounds.h));
// Add the image into the sprite's stock too.
int imageIndex = flatLayer->sprite()->stock()->addImage(imageWrap);
Image* image = imageWrap.release();
ImageRef image(Image::create(flatLayer->sprite()->pixelFormat(), bounds.w, bounds.h));
// Create the new cel for the output layer.
base::UniquePtr<Cel> cel(new Cel(frame, imageIndex));
base::UniquePtr<Cel> cel(new Cel(frame, image));
cel->setPosition(bounds.x, bounds.y);
// Render this frame.

View File

@ -47,7 +47,6 @@
#include "doc/image_bits.h"
#include "doc/palette.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "ui/ui.h"
namespace app {
@ -243,12 +242,9 @@ void ColorSelector::onFixWarningClick(ui::Event& ev)
if (sprite->pixelFormat() == IMAGE_INDEXED) {
lastUsed = sprite->transparentColor();
Stock* stock = sprite->stock();
for (int i=0; i<(int)stock->size(); ++i) {
Image* image = stock->getImage(i);
if (!image)
continue;
std::vector<Image*> images;
sprite->getImages(images);
for (Image* image : images) {
const LockImageBits<IndexedTraits> bits(image);
for (LockImageBits<IndexedTraits>::const_iterator it=bits.begin(); it!=bits.end(); ++it) {
if (lastUsed < *it)

View File

@ -1214,19 +1214,13 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
style = m_timelineEmptyFrameStyle;
}
else {
#if 0 // TODO We must find a fast-way to compare keyframes. Cels could
// share images until the user draw over them. Also, we could
// calculate a hash for each image (and recalculate it when the
// user draw over it), so then we can compare hashes. Other
// option is to use a thread to calculate differences, but I
// think it's too much for just UI stuff.
Layer* layer = m_layers[layerIndex];
Cel* left = (layer->isImage() ? static_cast<LayerImage*>(layer)->getCel(frame-1): NULL);
Cel* right = (layer->isImage() ? static_cast<LayerImage*>(layer)->getCel(frame+1): NULL);
Image* leftImg = (left ? m_sprite->stock()->getImage(left->getImage()): NULL);
Image* rightImg = (right ? m_sprite->stock()->getImage(right->getImage()): NULL);
bool fromLeft = (leftImg && count_diff_between_images(image, leftImg) == 0);
bool fromRight = (rightImg && count_diff_between_images(image, rightImg) == 0);
Cel* left = (layer->isImage() ? layer->cel(frame-1): NULL);
Cel* right = (layer->isImage() ? layer->cel(frame+1): NULL);
ObjectId leftImg = (left ? left->image()->id(): 0);
ObjectId rightImg = (right ? right->image()->id(): 0);
bool fromLeft = (leftImg == cel->image()->id());
bool fromRight = (rightImg == cel->image()->id());
if (fromLeft && fromRight)
style = m_timelineFromBothStyle;
@ -1235,7 +1229,6 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
else if (fromRight)
style = m_timelineFromRightStyle;
else
#endif
style = m_timelineKeyframeStyle;
}
drawPart(g, bounds, NULL, style, is_active, is_hover);

View File

@ -1,63 +0,0 @@
/* Aseprite
* Copyright (C) 2001-2013 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/undoers/add_image.h"
#include "app/undoers/remove_image.h"
#include "doc/image.h"
#include "doc/stock.h"
#include "undo/objects_container.h"
#include "undo/undo_exception.h"
#include "undo/undoers_collector.h"
namespace app {
namespace undoers {
using namespace undo;
AddImage::AddImage(ObjectsContainer* objects, Stock* stock, int imageIndex)
: m_stockId(objects->addObject(stock))
, m_imageIndex(imageIndex)
{
}
void AddImage::dispose()
{
delete this;
}
void AddImage::revert(ObjectsContainer* objects, UndoersCollector* redoers)
{
Stock* stock = objects->getObjectT<Stock>(m_stockId);
Image* image = stock->getImage(m_imageIndex);
if (image == NULL)
throw UndoException("One image was not found in the stock");
redoers->pushUndoer(new RemoveImage(objects, stock, m_imageIndex));
stock->removeImage(image);
delete image;
}
} // namespace undoers
} // namespace app

View File

@ -1,51 +0,0 @@
/* Aseprite
* Copyright (C) 2001-2013 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
*/
#ifndef APP_UNDOERS_ADD_IMAGE_H_INCLUDED
#define APP_UNDOERS_ADD_IMAGE_H_INCLUDED
#pragma once
#include "app/undoers/undoer_base.h"
#include "undo/object_id.h"
namespace doc {
class Stock;
}
namespace app {
namespace undoers {
using namespace doc;
using namespace undo;
class AddImage : public UndoerBase {
public:
AddImage(ObjectsContainer* objects, Stock* stock, int imageIndex);
void dispose() override;
size_t getMemSize() const override { return sizeof(*this); }
void revert(ObjectsContainer* objects, UndoersCollector* redoers) override;
private:
undo::ObjectId m_stockId;
uint32_t m_imageIndex;
};
} // namespace undoers
} // namespace app
#endif // UNDOERS_ADD_IMAGE_H_INCLUDED

View File

@ -0,0 +1,86 @@
/* Aseprite
* Copyright (C) 2001-2013 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/undoers/object_io.h"
#include "doc/cel.h"
#include "doc/cel_io.h"
#include "doc/image.h"
#include "doc/image_io.h"
#include "doc/layer.h"
#include "doc/layer_io.h"
namespace app {
namespace undoers {
using namespace undo;
ObjectIO::ObjectIO(ObjectsContainer* objects, Sprite* sprite)
: m_objects(objects)
, m_sprite(sprite)
{
}
ObjectIO::~ObjectIO()
{
}
void ObjectIO::write_cel(std::ostream& os, Cel* cel)
{
write_object(os, cel, [this](std::ostream& os, Cel* cel) {
doc::write_cel(os, this, cel);
});
}
void ObjectIO::write_image(std::ostream& os, Image* image)
{
write_object(os, image, doc::write_image);
}
void ObjectIO::write_layer(std::ostream& os, Layer* layer)
{
write_object(os, layer, [this](std::ostream& os, Layer* layer) {
doc::write_layer(os, this, layer);
});
}
Cel* ObjectIO::read_cel(std::istream& is)
{
return read_object<Cel>(is, [this](std::istream& is) {
return doc::read_cel(is, this, m_sprite);
});
}
Image* ObjectIO::read_image(std::istream& is)
{
return read_object<Image>(is, doc::read_image);
}
Layer* ObjectIO::read_layer(std::istream& is)
{
return read_object<Layer>(is, [this](std::istream& is) {
return doc::read_layer(is, this, m_sprite);
});
}
} // namespace undoers
} // namespace app

View File

@ -22,10 +22,37 @@
#include "base/serialization.h"
#include "base/unique_ptr.h"
#include "doc/subobjects_io.h"
#include "undo/objects_container.h"
namespace doc {
class Cel;
class Image;
class Layer;
class Sprite;
}
namespace app {
namespace undoers {
namespace undoers {
using namespace doc;
using namespace undo;
class ObjectIO : public SubObjectsIO {
public:
ObjectIO(ObjectsContainer* objects, Sprite* sprite);
virtual ~ObjectIO();
// How to write cels, images, and sub-layers
void write_cel(std::ostream& os, Cel* cel) override;
void write_image(std::ostream& os, Image* image) override;
void write_layer(std::ostream& os, Layer* layer) override;
// How to read cels, images, and sub-layers
Cel* read_cel(std::istream& is) override;
Image* read_image(std::istream& is) override;
Layer* read_layer(std::istream& is) override;
private:
// read_object and write_object functions can be used to serialize an
// object into a stream, and restore it back into the memory with the
@ -35,37 +62,41 @@ namespace app {
// ID from the ObjectsContainer. When the object is deserialized with
// read_object, the object is added to the container with the same ID.
template<class T, class Writer>
void write_object(undo::ObjectsContainer* objects, std::ostream& os, T* object, Writer& writer)
void write_object(std::ostream& os, T* object, Writer writer)
{
using base::serialization::little_endian::write32;
// Get an ID for the image.
undo::ObjectId objectId = objects->addObject(object);
undo::ObjectId objectId = m_objects->addObject(object);
write32(os, objectId); // Write the ID
writer(os, object); // Write the object
// Remove the object from the container (it will be
// re-added by a undoers::read_object call).
objects->removeObject(objectId);
m_objects->removeObject(objectId);
}
// Deserializes the given object from the stream, adding the object
// into the ObjectsContainer with the same ID saved with write_object().
template<class T, class Reader>
T* read_object(undo::ObjectsContainer* objects, std::istream& is, Reader& reader)
T* read_object(std::istream& is, Reader reader)
{
using base::serialization::little_endian::read32;
undo::ObjectId objectId = read32(is); // Read the ID
base::UniquePtr<T> object(reader(is)); // Read the object
base::UniquePtr<T> object(reader(is)); // Read the object
// Re-insert the object in the container with the read ID.
objects->insertObject(objectId, object);
m_objects->insertObject(objectId, object);
return object.release();
}
} // namespace undoers
ObjectsContainer* m_objects;
Sprite* m_sprite;
};
} // namespace undoers
} // namespace app
#endif // UNDOERS_OBJECT_IO_H_INCLUDED

View File

@ -25,9 +25,7 @@
#include "app/undoers/add_cel.h"
#include "app/undoers/object_io.h"
#include "doc/cel.h"
#include "doc/cel_io.h"
#include "doc/layer.h"
#include "doc/stock.h"
#include "undo/objects_container.h"
#include "undo/undoers_collector.h"
@ -40,7 +38,7 @@ using namespace undo;
RemoveCel::RemoveCel(ObjectsContainer* objects, Layer* layer, Cel* cel)
: m_layerId(objects->addObject(layer))
{
write_object(objects, m_stream, cel, doc::write_cel);
ObjectIO(objects, layer->sprite()).write_cel(m_stream, cel);
}
void RemoveCel::dispose()
@ -51,9 +49,8 @@ void RemoveCel::dispose()
void RemoveCel::revert(ObjectsContainer* objects, UndoersCollector* redoers)
{
LayerImage* layer = objects->getObjectT<LayerImage>(m_layerId);
Cel* cel = read_object<Cel>(objects, m_stream, doc::read_cel);
Cel* cel = ObjectIO(objects, layer->sprite()).read_cel(m_stream);
// Push an AddCel as redoer
redoers->pushUndoer(new AddCel(objects, layer, cel));
layer->addCel(cel);

View File

@ -1,65 +0,0 @@
/* Aseprite
* Copyright (C) 2001-2013 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/undoers/remove_image.h"
#include "app/undoers/add_image.h"
#include "app/undoers/object_io.h"
#include "doc/image.h"
#include "doc/image_io.h"
#include "doc/stock.h"
#include "undo/objects_container.h"
#include "undo/undoers_collector.h"
namespace app {
namespace undoers {
using namespace doc;
using namespace undo;
RemoveImage::RemoveImage(ObjectsContainer* objects, Stock* stock, int imageIndex)
: m_stockId(objects->addObject(stock))
, m_imageIndex(imageIndex)
{
Image* image = stock->getImage(imageIndex);
write_object(objects, m_stream, image, doc::write_image);
}
void RemoveImage::dispose()
{
delete this;
}
void RemoveImage::revert(ObjectsContainer* objects, UndoersCollector* redoers)
{
Stock* stock = objects->getObjectT<Stock>(m_stockId);
Image* image = read_object<Image>(objects, m_stream, doc::read_image);
// Push an AddImage as redoer
redoers->pushUndoer(new AddImage(objects, stock, m_imageIndex));
stock->replaceImage(m_imageIndex, image);
}
} // namespace undoers
} // namespace app

View File

@ -1,58 +0,0 @@
/* Aseprite
* Copyright (C) 2001-2013 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
*/
#ifndef APP_UNDOERS_REMOVE_IMAGE_H_INCLUDED
#define APP_UNDOERS_REMOVE_IMAGE_H_INCLUDED
#pragma once
#include "app/undoers/undoer_base.h"
#include "undo/object_id.h"
#include <sstream>
namespace doc {
class Stock;
}
namespace app {
namespace undoers {
using namespace doc;
using namespace undo;
class RemoveImage : public UndoerBase {
public:
RemoveImage(ObjectsContainer* objects, Stock* stock, int imageIndex);
void dispose() override;
size_t getMemSize() const override { return sizeof(*this) + getStreamSize(); }
void revert(ObjectsContainer* objects, UndoersCollector* redoers) override;
private:
size_t getStreamSize() const {
return const_cast<std::stringstream*>(&m_stream)->tellp();
}
undo::ObjectId m_stockId;
uint32_t m_imageIndex;
std::stringstream m_stream;
};
} // namespace undoers
} // namespace app
#endif // UNDOERS_REMOVE_IMAGE_H_INCLUDED

View File

@ -27,11 +27,8 @@
#include "app/undoers/add_layer.h"
#include "app/undoers/object_io.h"
#include "doc/cel.h"
#include "doc/cel_io.h"
#include "doc/image.h"
#include "doc/image_io.h"
#include "doc/layer.h"
#include "doc/layer_io.h"
#include "undo/objects_container.h"
#include "undo/undoers_collector.h"
@ -40,58 +37,6 @@ namespace undoers {
using namespace undo;
class LayerSubObjectsSerializerImpl : public doc::LayerSubObjectsSerializer {
public:
LayerSubObjectsSerializerImpl(ObjectsContainer* objects, Sprite* sprite)
: m_objects(objects)
, m_sprite(sprite) {
}
virtual ~LayerSubObjectsSerializerImpl() { }
// How to write cels, images, and sub-layers
void write_cel(std::ostream& os, Cel* cel) override {
write_object(m_objects, os, cel, doc::write_cel);
}
void write_image(std::ostream& os, Image* image) override {
write_object(m_objects, os, image, doc::write_image);
}
void write_layer(std::ostream& os, Layer* layer) override {
// To write a sub-layer we use the operator() of this instance (*this)
write_object(m_objects, os, layer, *this);
}
// How to read cels, images, and sub-layers
Cel* read_cel(std::istream& is) override {
return read_object<Cel>(m_objects, is, doc::read_cel);
}
Image* read_image(std::istream& is) override {
return read_object<Image>(m_objects, is, doc::read_image);
}
Layer* read_layer(std::istream& is) override {
// To read a sub-layer we use the operator() of this instance (*this)
return read_object<Layer>(m_objects, is, *this);
}
// The following operator() calls are used in write/read_object() functions.
void operator()(std::ostream& os, Layer* layer) {
doc::write_layer(os, this, layer);
}
Layer* operator()(std::istream& is) {
return doc::read_layer(is, this, m_sprite);
}
private:
ObjectsContainer* m_objects;
Sprite* m_sprite;
};
RemoveLayer::RemoveLayer(ObjectsContainer* objects, Document* document, Layer* layer)
: m_documentId(objects->addObject(document))
, m_folderId(objects->addObject(layer->parent()))
@ -99,8 +44,7 @@ RemoveLayer::RemoveLayer(ObjectsContainer* objects, Document* document, Layer* l
Layer* after = layer->getPrevious();
m_afterId = (after ? objects->addObject(after): 0);
LayerSubObjectsSerializerImpl serializer(objects, layer->sprite());
write_object(objects, m_stream, layer, serializer);
ObjectIO(objects, layer->sprite()).write_layer(m_stream, layer);
}
void RemoveLayer::dispose()
@ -115,8 +59,8 @@ void RemoveLayer::revert(ObjectsContainer* objects, UndoersCollector* redoers)
Layer* after = (m_afterId != 0 ? objects->getObjectT<Layer>(m_afterId): NULL);
// Read the layer from the stream
LayerSubObjectsSerializerImpl serializer(objects, folder->sprite());
Layer* layer = read_object<Layer>(objects, m_stream, serializer);
Layer* layer =
ObjectIO(objects, folder->sprite()).read_layer(m_stream);
document->getApi(redoers).addLayer(folder, layer, after);
}

View File

@ -25,7 +25,8 @@
#include "app/undoers/object_io.h"
#include "doc/image.h"
#include "doc/image_io.h"
#include "doc/stock.h"
#include "doc/image_ref.h"
#include "doc/sprite.h"
#include "undo/objects_container.h"
#include "undo/undoers_collector.h"
@ -34,13 +35,12 @@ namespace undoers {
using namespace undo;
ReplaceImage::ReplaceImage(ObjectsContainer* objects, Stock* stock, int imageIndex)
: m_stockId(objects->addObject(stock))
, m_imageIndex(imageIndex)
ReplaceImage::ReplaceImage(ObjectsContainer* objects, Sprite* sprite,
Image* oldImage, Image* newImage)
: m_spriteId(objects->addObject(sprite))
, m_newImageId(objects->addObject(newImage))
{
Image* image = stock->getImage(imageIndex);
write_object(objects, m_stream, image, doc::write_image);
ObjectIO(objects, sprite).write_image(m_stream, oldImage);
}
void ReplaceImage::dispose()
@ -50,20 +50,23 @@ void ReplaceImage::dispose()
void ReplaceImage::revert(ObjectsContainer* objects, UndoersCollector* redoers)
{
Stock* stock = objects->getObjectT<Stock>(m_stockId);
Sprite* sprite = objects->getObjectT<Sprite>(m_spriteId);
Image* currentImageRaw = objects->getObjectT<Image>(m_newImageId);
ASSERT(currentImageRaw != NULL);
ImageRef currentImage = sprite->getImage(currentImageRaw->id());
ASSERT(currentImage != NULL);
// Read the image to be restored from the stream
Image* image = read_object<Image>(objects, m_stream, doc::read_image);
ImageRef restoreImage(
ObjectIO(objects, sprite).read_image(m_stream));
// Save the current image in the redoers
redoers->pushUndoer(new ReplaceImage(objects, stock, m_imageIndex));
Image* oldImage = stock->getImage(m_imageIndex);
redoers->pushUndoer(new ReplaceImage(objects, sprite,
currentImage, restoreImage));
// Replace the image in the stock
stock->replaceImage(m_imageIndex, image);
// Destroy the old image
delete oldImage;
sprite->replaceImage(currentImage->id(), restoreImage);
}
} // namespace undoers

View File

@ -26,7 +26,8 @@
#include <sstream>
namespace doc {
class Stock;
class Image;
class Sprite;
}
namespace app {
@ -36,7 +37,8 @@ namespace app {
class ReplaceImage : public UndoerBase {
public:
ReplaceImage(ObjectsContainer* objects, Stock* stock, int imageIndex);
ReplaceImage(ObjectsContainer* objects, Sprite* sprite,
Image* oldImage, Image* newImage);
void dispose() override;
size_t getMemSize() const override { return sizeof(*this) + getStreamSize(); }
@ -47,8 +49,8 @@ namespace app {
return const_cast<std::stringstream*>(&m_stream)->tellp();
}
undo::ObjectId m_stockId;
uint32_t m_imageIndex;
undo::ObjectId m_spriteId;
undo::ObjectId m_newImageId;
std::stringstream m_stream;
};

View File

@ -40,7 +40,6 @@
#include "app/ui/timeline.h"
#include "app/ui_context.h"
#include "app/undo_transaction.h"
#include "app/undoers/add_image.h"
#include "app/undoers/image_area.h"
#include "app/util/clipboard.h"
#include "app/util/misc.h"

View File

@ -28,7 +28,6 @@
#include "app/document_location.h"
#include "app/undo_transaction.h"
#include "app/undoers/add_cel.h"
#include "app/undoers/add_image.h"
#include "app/undoers/dirty_area.h"
#include "app/undoers/modified_region.h"
#include "app/undoers/replace_image.h"
@ -40,7 +39,6 @@
#include "doc/layer.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace {
@ -88,14 +86,14 @@ ExpandCelCanvas::ExpandCelCanvas(Context* context, TiledMode tiledMode, UndoTran
if (m_layer->isImage()) {
m_cel = m_layer->cel(location.frame());
if (m_cel)
m_celImage = m_cel->image();
m_celImage = m_cel->imageRef();
}
// If there is no Cel
if (m_cel == NULL) {
// Create the cel
m_celCreated = true;
m_cel = new Cel(location.frame(), 0);
m_cel = new Cel(location.frame(), ImageRef(NULL));
static_cast<LayerImage*>(m_layer)->addCel(m_cel);
}
@ -152,25 +150,21 @@ void ExpandCelCanvas::commit()
// don't have a m_celImage)
validateDestCanvas(gfx::Region(m_bounds));
// We can temporary remove the cel.
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
// Add a copy of m_dstImage in the sprite's image stock
m_cel->setImage(m_sprite->stock()->addImage(
Image::createCopy(m_dstImage)));
ImageRef newImage(Image::createCopy(m_dstImage));
m_cel->setImage(newImage);
// Is the undo enabled?.
if (m_undo.isEnabled()) {
// We can temporary remove the cel.
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
// We create the undo information (for the new m_celImage
// in the stock and the new cel in the layer)...
m_undo.pushUndoer(new undoers::AddImage(m_undo.getObjects(),
m_sprite->stock(), m_cel->imageIndex()));
m_undo.pushUndoer(new undoers::AddCel(m_undo.getObjects(),
m_layer, m_cel));
// And finally we add the cel again in the layer.
static_cast<LayerImage*>(m_layer)->addCel(m_cel);
}
// And finally we add the cel again in the layer.
static_cast<LayerImage*>(m_layer)->addCel(m_cel);
}
else if (m_celImage) {
// If the size of each image is the same, we can create an undo
@ -206,9 +200,6 @@ void ExpandCelCanvas::commit()
m_undo.pushUndoer(new undoers::SetCelPosition(m_undo.getObjects(), m_cel));
m_cel->setPosition(newPos);
}
m_undo.pushUndoer(new undoers::ReplaceImage(m_undo.getObjects(),
m_sprite->stock(), m_cel->imageIndex()));
}
// Validate the whole m_dstImage copying invalid areas from m_celImage
@ -216,11 +207,13 @@ void ExpandCelCanvas::commit()
// Replace the image in the stock. We need to create a copy of
// image because m_dstImage's ImageBuffer cannot be shared.
m_sprite->stock()->replaceImage(m_cel->imageIndex(),
Image::createCopy(m_dstImage));
ImageRef newImage(Image::createCopy(m_dstImage));
// Destroy the old cel image.
delete m_celImage;
if (m_undo.isEnabled())
m_undo.pushUndoer(new undoers::ReplaceImage(m_undo.getObjects(),
m_sprite, m_celImage, newImage));
m_sprite->replaceImage(m_celImage->id(), newImage);
}
}
else {
@ -241,7 +234,7 @@ void ExpandCelCanvas::rollback()
if (m_celCreated) {
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
delete m_cel;
delete m_celImage;
m_celImage.reset(NULL);
}
m_closed = true;

View File

@ -20,6 +20,7 @@
#define APP_UTIL_EXPAND_CEL_CANVAS_H_INCLUDED
#pragma once
#include "doc/image_ref.h"
#include "filters/tiled_mode.h"
#include "gfx/point.h"
#include "gfx/rect.h"
@ -85,7 +86,7 @@ namespace app {
Sprite* m_sprite;
Layer* m_layer;
Cel* m_cel;
Image* m_celImage;
ImageRef m_celImage;
bool m_celCreated;
gfx::Point m_origCelPos;
gfx::Point m_celPos;

View File

@ -38,5 +38,4 @@ add_library(doc-lib
primitives.cpp
rgbmap.cpp
sprite.cpp
sprites.cpp
stock.cpp)
sprites.cpp)

View File

@ -14,11 +14,10 @@
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace doc {
Cel::Cel(frame_t frame, int image)
Cel::Cel(frame_t frame, const ImageRef& image)
: Object(ObjectType::Cel)
, m_layer(NULL)
, m_frame(frame)
@ -42,26 +41,16 @@ Cel::~Cel()
{
}
Image* Cel::image() const
void Cel::setFrame(frame_t frame)
{
ASSERT(m_layer != NULL);
ASSERT(m_image >= 0);
ASSERT(m_image < m_layer->sprite()->stock()->size());
ASSERT(m_layer == NULL);
m_frame = frame;
}
if (m_layer) {
Stock* stock = m_layer->sprite()->stock();
ASSERT(stock);
ASSERT(m_image >= 0 && m_image < stock->size());
if (m_image >= 0 && m_image < stock->size()) {
Image* image = stock->getImage(m_image);
ASSERT((m_image == 0 && !image) || (m_image != 0 && image));
return image;
}
}
return NULL;
void Cel::setImage(const ImageRef& image)
{
m_image = image;
fixupImage();
}
Sprite* Cel::sprite() const
@ -73,6 +62,22 @@ Sprite* Cel::sprite() const
return NULL;
}
Cel* Cel::link() const
{
if (m_image.get() == NULL)
return NULL;
if (!m_image.unique()) {
for (frame_t fr=0; fr<m_frame; ++fr) {
Cel* possible = m_layer->cel(fr);
if (possible && possible->imageRef().get() == m_image.get())
return possible;
}
}
return NULL;
}
gfx::Rect Cel::bounds() const
{
Image* image = this->image();
@ -85,4 +90,17 @@ gfx::Rect Cel::bounds() const
return gfx::Rect();
}
void Cel::setParentLayer(LayerImage* layer)
{
m_layer = layer;
fixupImage();
}
void Cel::fixupImage()
{
// Change the mask color to the sprite mask color
if (m_layer && m_image.get())
m_image->setMaskColor(m_layer->sprite()->transparentColor());
}
} // namespace doc

View File

@ -9,39 +9,40 @@
#pragma once
#include "doc/frame.h"
#include "doc/image_ref.h"
#include "doc/object.h"
#include "gfx/fwd.h"
#include "gfx/point.h"
namespace doc {
class Image;
class LayerImage;
class Sprite;
class Cel : public Object {
public:
Cel(frame_t frame, int image);
Cel(frame_t frame, const ImageRef& image);
Cel(const Cel& cel);
virtual ~Cel();
frame_t frame() const { return m_frame; }
int imageIndex() const { return m_image; }
int x() const { return m_position.x; }
int y() const { return m_position.y; }
gfx::Point position() const { return m_position; }
int opacity() const { return m_opacity; }
LayerImage* layer() const { return m_layer; }
Image* image() const;
Image* image() const { return const_cast<Image*>(m_image.get()); };
ImageRef imageRef() const { return m_image; }
Sprite* sprite() const;
Cel* link() const;
gfx::Rect bounds() const;
// You should change the frame only if the cel isn't member of a
// layer. If the cel is already in a layer, you should use
// LayerImage::moveCel() member function.
void setFrame(frame_t frame) { m_frame = frame; }
void setImage(int image) { m_image = image; }
void setFrame(frame_t frame);
void setImage(const ImageRef& image);
void setPosition(int x, int y) {
m_position.x = x;
m_position.y = y;
@ -53,14 +54,14 @@ namespace doc {
return sizeof(Cel);
}
void setParentLayer(LayerImage* layer) {
m_layer = layer;
}
void setParentLayer(LayerImage* layer);
private:
void fixupImage();
LayerImage* m_layer;
frame_t m_frame; // Frame position
int m_image; // Image index of stock
ImageRef m_image;
gfx::Point m_position; // X/Y screen position
int m_opacity; // Opacity level
};

View File

@ -13,6 +13,8 @@
#include "base/serialization.h"
#include "base/unique_ptr.h"
#include "doc/cel.h"
#include "doc/sprite.h"
#include "doc/subobjects_io.h"
#include <iostream>
@ -21,43 +23,41 @@ namespace doc {
using namespace base::serialization;
using namespace base::serialization::little_endian;
// Serialized Cel data:
//
// WORD Frame
// WORD Image index
// WORD[2] X, Y
// WORD Opacity
void write_cel(std::ostream& os, Cel* cel)
void write_cel(std::ostream& os, SubObjectsIO* subObjects, Cel* cel)
{
// ObjectId cel_id = objects->addObject(cel);
// write_raw_uint32(cel_id);
Cel* link = cel->link();
write16(os, cel->frame());
write16(os, cel->imageIndex());
write16(os, (int16_t)cel->x());
write16(os, (int16_t)cel->y());
write16(os, cel->opacity());
// objects->removeObject(cel_id);
write16(os, link ? 1: 0);
if (link)
write32(os, link->id());
else
subObjects->write_image(os, cel->image());
}
Cel* read_cel(std::istream& is)
Cel* read_cel(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
{
// ObjectId cel_id = read32();
frame_t frame(read16(is));
int imageIndex = read16(is);
int x = (int16_t)read16(is);
int y = (int16_t)read16(is);
int opacity = read16(is);
bool is_link = (read16(is) == 1);
base::UniquePtr<Cel> cel(new Cel(frame, imageIndex));
base::UniquePtr<Cel> cel(new Cel(frame, ImageRef(NULL)));
cel->setPosition(x, y);
cel->setOpacity(opacity);
// objects->insertObject(cel_id, cel);
if (is_link) {
ObjectId imageId = read32(is);
cel->setImage(sprite->getImage(imageId));
}
else
cel->setImage(ImageRef(subObjects->read_image(is)));
return cel.release();
}

View File

@ -13,9 +13,11 @@
namespace doc {
class Cel;
class Sprite;
class SubObjectsIO;
void write_cel(std::ostream& os, Cel* cel);
Cel* read_cel(std::istream& is);
void write_cel(std::ostream& os, SubObjectsIO* subObjects, Cel* cel);
Cel* read_cel(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite);
} // namespace doc

View File

@ -27,6 +27,5 @@
#include "doc/primitives_fast.h"
#include "doc/rgbmap.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#endif

20
src/doc/image_ref.h Normal file
View File

@ -0,0 +1,20 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_IMAGE_REF_H_INCLUDED
#define DOC_IMAGE_REF_H_INCLUDED
#pragma once
#include "base/shared_ptr.h"
#include "doc/image.h"
namespace doc {
typedef SharedPtr<Image> ImageRef;
} // namespace doc
#endif

View File

@ -14,7 +14,6 @@
#include "doc/layer.h"
#include "doc/mask.h"
#include "doc/sprite.h"
#include "doc/stock.h"
namespace doc {

View File

@ -15,7 +15,6 @@
#include "doc/image.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include <algorithm>
#include <string.h>
@ -118,12 +117,6 @@ void LayerImage::destroyAllCels()
for (; it != end; ++it) {
Cel* cel = *it;
Image* image = cel->image();
ASSERT(image != NULL);
sprite()->stock()->removeImage(image);
delete image;
delete cel;
}
m_cels.clear();
@ -181,13 +174,15 @@ void LayerImage::addCel(Cel *cel)
* It doesn't destroy the cel, you have to delete it after calling
* this routine.
*/
void LayerImage::removeCel(Cel *cel)
void LayerImage::removeCel(Cel* cel)
{
CelIterator it = std::find(m_cels.begin(), m_cels.end(), cel);
ASSERT(it != m_cels.end());
m_cels.erase(it);
cel->setParentLayer(NULL);
}
void LayerImage::moveCel(Cel* cel, frame_t frame)

View File

@ -15,7 +15,7 @@
#include "doc/cel.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include "doc/stock.h"
#include "doc/subobjects_io.h"
#include <iostream>
#include <vector>
@ -27,7 +27,7 @@ using namespace base::serialization::little_endian;
// Serialized Layer data:
void write_layer(std::ostream& os, LayerSubObjectsSerializer* subObjects, Layer* layer)
void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer)
{
std::string name = layer->name();
@ -50,11 +50,6 @@ void write_layer(std::ostream& os, LayerSubObjectsSerializer* subObjects, Layer*
for (; it != end; ++it) {
Cel* cel = *it;
subObjects->write_cel(os, cel);
Image* image = cel->image();
ASSERT(image != NULL);
subObjects->write_image(os, image);
}
break;
}
@ -74,7 +69,7 @@ void write_layer(std::ostream& os, LayerSubObjectsSerializer* subObjects, Layer*
}
}
Layer* read_layer(std::istream& is, LayerSubObjectsSerializer* subObjects, Sprite* sprite)
Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
{
uint16_t name_length = read16(is); // Name length
std::vector<char> name(name_length+1);
@ -104,11 +99,6 @@ Layer* read_layer(std::istream& is, LayerSubObjectsSerializer* subObjects, Sprit
// Add the cel in the layer
static_cast<LayerImage*>(layer.get())->addCel(cel);
// Read the cel's image
Image* image = subObjects->read_image(is);
sprite->stock()->replaceImage(cel->imageIndex(), image);
}
break;
}

View File

@ -18,6 +18,7 @@ namespace doc {
class Image;
class Layer;
class Sprite;
class SubObjectsIO;
// Thrown when a invalid layer type is read from the istream.
class InvalidLayerType : public base::Exception {
@ -25,24 +26,8 @@ namespace doc {
InvalidLayerType(const char* msg) throw() : base::Exception(msg) { }
};
// Interface used to read sub-objects of a layer.
class LayerSubObjectsSerializer {
public:
virtual ~LayerSubObjectsSerializer() { }
// How to write cels, images, and sub-layers
virtual void write_cel(std::ostream& os, Cel* cel) = 0;
virtual void write_image(std::ostream& os, Image* image) = 0;
virtual void write_layer(std::ostream& os, Layer* layer) = 0;
// How to read cels, images, and sub-layers
virtual Cel* read_cel(std::istream& is) = 0;
virtual Image* read_image(std::istream& is) = 0;
virtual Layer* read_layer(std::istream& is) = 0;
};
void write_layer(std::ostream& os, LayerSubObjectsSerializer* subObjects, Layer* layer);
Layer* read_layer(std::istream& is, LayerSubObjectsSerializer* subObjects, Sprite* sprite);
void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer);
Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite);
} // namespace doc

View File

@ -20,7 +20,6 @@ namespace doc {
Cel,
LayerImage,
LayerFolder,
Stock,
Sprite,
Document,
};

View File

@ -38,7 +38,6 @@ Sprite::Sprite(PixelFormat format, int width, int height, int ncolors)
ASSERT(width > 0 && height > 0);
m_frlens.push_back(100); // First frame with 100 msecs of duration
m_stock = new Stock(this, format);
m_folder = new LayerFolder(this);
// Generate palette
@ -77,10 +76,6 @@ Sprite::~Sprite()
// Destroy layers
delete m_folder;
// Destroy images' stock
if (m_stock)
delete m_stock;
// Destroy palettes
{
PalettesList::iterator end = m_palettes.end();
@ -101,17 +96,8 @@ Sprite* Sprite::createBasicSprite(doc::PixelFormat format, int width, int height
sprite->setTotalFrames(doc::frame_t(1));
// Create the main image.
int indexInStock;
{
base::UniquePtr<doc::Image> image(doc::Image::create(format, width, height));
// Clear the image with mask color.
doc::clear_image(image, 0);
// Add image in the sprite's stock.
indexInStock = sprite->stock()->addImage(image);
image.release(); // Release the image because it is in the sprite's stock.
}
doc::ImageRef image(doc::Image::create(format, width, height));
doc::clear_image(image, 0);
// Create the first transparent layer.
{
@ -120,7 +106,7 @@ Sprite* Sprite::createBasicSprite(doc::PixelFormat format, int width, int height
// Create the cel.
{
base::UniquePtr<doc::Cel> cel(new doc::Cel(doc::frame_t(0), indexInStock));
base::UniquePtr<doc::Cel> cel(new doc::Cel(doc::frame_t(0), image));
cel->setPosition(0, 0);
// Add the cel in the layer.
@ -177,22 +163,20 @@ void Sprite::setTransparentColor(color_t color)
m_transparentColor = color;
// Change the mask color of all images.
for (int i=0; i<m_stock->size(); i++) {
Image* image = m_stock->getImage(i);
if (image != NULL)
image->setMaskColor(color);
}
std::vector<Image*> images;
getImages(images);
for (Image* image : images)
image->setMaskColor(color);
}
int Sprite::getMemSize() const
{
int size = 0;
for (int i=0; i<m_stock->size(); i++) {
Image* image = m_stock->getImage(i);
if (image != NULL)
size += image->getRowStrideSize() * image->height();
}
std::vector<Image*> images;
getImages(images);
for (Image* image : images)
size += image->getRowStrideSize() * image->height();
return size;
}
@ -410,9 +394,25 @@ void Sprite::setDurationForAllFrames(int msecs)
//////////////////////////////////////////////////////////////////////
// Images
Stock* Sprite::stock() const
ImageRef Sprite::getImage(ObjectId imageId)
{
return m_stock;
CelList cels;
getCels(cels);
for (auto& cel : cels) {
if (cel->image()->id() == imageId)
return cel->imageRef();
}
return ImageRef(NULL);
}
void Sprite::replaceImage(ObjectId curImageId, const ImageRef& newImage)
{
CelList cels;
getCels(cels);
for (auto& cel : cels) {
if (cel->image()->id() == curImageId)
cel->setImage(newImage);
}
}
void Sprite::getCels(CelList& cels) const
@ -420,17 +420,15 @@ void Sprite::getCels(CelList& cels) const
folder()->getCels(cels);
}
size_t Sprite::getImageRefs(int imageIndex) const
// TODO replace it with a images iterator
void Sprite::getImages(std::vector<Image*>& images) const
{
CelList cels;
getCels(cels);
getCels(cels); // TODO create a cel iterator
size_t refs = 0;
for (CelList::iterator it=cels.begin(), end=cels.end(); it != end; ++it)
if ((*it)->imageIndex() == imageIndex)
++refs;
return refs;
for (const auto& cel : cels)
if (!cel->link())
images.push_back(cel->image());
}
void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const std::vector<uint8_t>& mapping)

View File

@ -12,6 +12,7 @@
#include "doc/cel_list.h"
#include "doc/color.h"
#include "doc/frame.h"
#include "doc/image_ref.h"
#include "doc/layer_index.h"
#include "doc/object.h"
#include "doc/pixel_format.h"
@ -31,7 +32,6 @@ namespace doc {
class Path;
class RgbMap;
class Sprite;
class Stock;
typedef std::vector<Palette*> PalettesList;
@ -116,26 +116,20 @@ namespace doc {
////////////////////////////////////////
// Images
Stock* stock() const;
ImageRef getImage(ObjectId imageId);
void replaceImage(ObjectId curImageId, const ImageRef& newImage);
void getCels(CelList& cels) const;
// Returns the how many cels are referencing the given imageIndex.
size_t getImageRefs(int imageIndex) const;
void getImages(std::vector<Image*>& images) const;
void remapImages(frame_t frameFrom, frame_t frameTo, const std::vector<uint8_t>& mapping);
void pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const;
private:
Sprite* m_self; // pointer to the Sprite
PixelFormat m_format; // pixel format
int m_width; // image width (in pixels)
int m_height; // image height (in pixels)
frame_t m_frames; // how many frames has this sprite
std::vector<int> m_frlens; // duration per frame
PalettesList m_palettes; // list of palettes
Stock* m_stock; // stock to get images
LayerFolder* m_folder; // main folder of layers
// Current rgb map

View File

@ -17,7 +17,6 @@
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/primitives.h"
#include "doc/stock.h"
#include <algorithm>

View File

@ -1,91 +0,0 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "doc/stock.h"
#include "doc/image.h"
#include "doc/sprite.h"
#include <cstring>
namespace doc {
Stock::Stock(Sprite* sprite, PixelFormat format)
: Object(ObjectType::Stock)
, m_format(format)
, m_sprite(sprite)
{
// Image with index=0 is always NULL.
m_image.push_back(NULL);
}
Stock::~Stock()
{
for (int i=0; i<size(); ++i) {
if (getImage(i))
delete getImage(i);
}
}
Sprite* Stock::sprite() const
{
return m_sprite;
}
Image* Stock::getImage(int index) const
{
ASSERT((index >= 0) && (index < size()));
return m_image[index];
}
int Stock::addImage(Image* image)
{
int i = m_image.size();
try {
m_image.resize(m_image.size()+1);
}
catch (...) {
delete image;
throw;
}
m_image[i] = image;
fixupImage(image);
return i;
}
void Stock::removeImage(Image* image)
{
for (int i=0; i<size(); i++)
if (m_image[i] == image) {
m_image[i] = NULL;
return;
}
ASSERT(false && "The specified image was not found");
}
void Stock::replaceImage(int index, Image* image)
{
ASSERT((index > 0) && (index < size()));
m_image[index] = image;
fixupImage(image);
}
void Stock::fixupImage(Image* image)
{
// Change the mask color of the added image to the sprite mask color.
if (image)
image->setMaskColor(m_sprite->transparentColor());
}
} // namespace doc

View File

@ -1,70 +0,0 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_STOCK_H_INCLUDED
#define DOC_STOCK_H_INCLUDED
#pragma once
#include "base/disable_copying.h"
#include "doc/object.h"
#include "doc/pixel_format.h"
#include <vector>
namespace doc {
class Image;
class Sprite;
typedef std::vector<Image*> ImagesList;
class Stock : public Object {
public:
Stock(Sprite* sprite, PixelFormat format);
virtual ~Stock();
Sprite* sprite() const;
// Returns the number of image in the stock.
int size() const {
return m_image.size();
}
// Returns the image in the "index" position
Image* getImage(int index) const;
// Adds a new image in the stock resizing the images-array. Returns
// the index/position in the stock (this index can be used with the
// Stock::getImage() function).
int addImage(Image* image);
// Removes a image from the stock, it doesn't resize the stock.
void removeImage(Image* image);
// Replaces the image in the stock in the "index" position with the
// new "image"; you must delete the old image before, e.g:
//
// Image* old_image = stock->getImage(index);
// if (old_image)
// delete old_image;
// stock->replaceImage(index, new_image);
//
void replaceImage(int index, Image* image);
private:
void fixupImage(Image* image);
PixelFormat m_format; // Type of images (all images in the stock must be of this type).
ImagesList m_image; // The images-array where the images are.
Sprite* m_sprite;
Stock();
DISABLE_COPYING(Stock);
};
} // namespace doc
#endif

37
src/doc/subobjects_io.h Normal file
View File

@ -0,0 +1,37 @@
// Aseprite Document Library
// Copyright (c) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_SUBOBJECTS_IO_H_INCLUDED
#define DOC_SUBOBJECTS_IO_H_INCLUDED
#pragma once
#include <iosfwd>
namespace doc {
class Cel;
class Image;
class Layer;
// Interface used to read sub-objects of a layer or cel.
class SubObjectsIO {
public:
virtual ~SubObjectsIO() { }
// How to write cels, images, and sub-layers
virtual void write_cel(std::ostream& os, Cel* cel) = 0;
virtual void write_image(std::ostream& os, Image* image) = 0;
virtual void write_layer(std::ostream& os, Layer* layer) = 0;
// How to read cels, images, and sub-layers
virtual Cel* read_cel(std::istream& is) = 0;
virtual Image* read_image(std::istream& is) = 0;
virtual Layer* read_layer(std::istream& is) = 0;
};
} // namespace doc
#endif

View File

@ -21,7 +21,6 @@ namespace doc {
class Palette;
class RgbMap;
class Sprite;
class Stock;
}
namespace render {