diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index f0c0c882f..aec4cfad3 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -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 diff --git a/src/app/commands/cmd_cel_properties.cpp b/src/app/commands/cmd_cel_properties.cpp index 218fc4cc5..f7fd4df2a 100644 --- a/src/app/commands/cmd_cel_properties.cpp +++ b/src/app/commands/cmd_cel_properties.cpp @@ -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 { diff --git a/src/app/commands/cmd_export_sprite_sheet.cpp b/src/app/commands/cmd_export_sprite_sheet.cpp index 2dc7ef5ef..c533df2c8 100644 --- a/src/app/commands/cmd_export_sprite_sheet.cpp +++ b/src/app/commands/cmd_export_sprite_sheet.cpp @@ -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 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 resultCel(new Cel(frame_t(0), indexInStock)); + base::UniquePtr resultCel(new Cel(frame_t(0), resultImage)); // Add the cel in the layer. api.addCel(resultLayer, resultCel); diff --git a/src/app/commands/cmd_flip.cpp b/src/app/commands/cmd_flip.cpp index c2d8cb318..48e873add 100644 --- a/src/app/commands/cmd_flip.cpp +++ b/src/app/commands/cmd_flip.cpp @@ -39,7 +39,6 @@ #include "doc/layer.h" #include "doc/mask.h" #include "doc/sprite.h" -#include "doc/stock.h" namespace app { diff --git a/src/app/commands/cmd_import_sprite_sheet.cpp b/src/app/commands/cmd_import_sprite_sheet.cpp index c67831f78..a864a9abf 100644 --- a/src/app/commands/cmd_import_sprite_sheet.cpp +++ b/src/app/commands/cmd_import_sprite_sheet.cpp @@ -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 animation; + std::vector 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; yheight(); y += m_rect.h) { for (int x=m_rect.x; xwidth(); x += m_rect.w) { - base::UniquePtr 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 resultCel(new Cel(frame_t(i), indexInStock)); + base::UniquePtr 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; igetPrevious(); - int index; for (frame_t frpos = 0; frpostotalFrames(); ++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); } } } diff --git a/src/app/commands/cmd_new_file.cpp b/src/app/commands/cmd_new_file.cpp index 6ceaae0db..739954ac8 100644 --- a/src/app/commands/cmd_new_file.cpp +++ b/src/app/commands/cmd_new_file.cpp @@ -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" diff --git a/src/app/commands/cmd_palette_editor.cpp b/src/app/commands/cmd_palette_editor.cpp index 6e921b7c0..b130272c6 100644 --- a/src/app/commands/cmd_palette_editor.cpp +++ b/src/app/commands/cmd_palette_editor.cpp @@ -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" diff --git a/src/app/commands/cmd_rotate.cpp b/src/app/commands/cmd_rotate.cpp index 10825b7dd..224b2d7e8 100644 --- a/src/app/commands/cmd_rotate.cpp +++ b/src/app/commands/cmd_rotate.cpp @@ -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()); diff --git a/src/app/commands/cmd_sprite_size.cpp b/src/app/commands/cmd_sprite_size.cpp index 733856e7d..3708685dc 100644 --- a/src/app/commands/cmd_sprite_size.cpp +++ b/src/app/commands/cmd_sprite_size.cpp @@ -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 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()); diff --git a/src/app/commands/filters/filter_manager_impl.cpp b/src/app/commands/filters/filter_manager_impl.cpp index 0e786f357..50d4b43de 100644 --- a/src/app/commands/filters/filter_manager_impl.cpp +++ b/src/app/commands/filters/filter_manager_impl.cpp @@ -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" diff --git a/src/app/context_flags.cpp b/src/app/context_flags.cpp index 8c8703d9d..20f243c56 100644 --- a/src/app/context_flags.cpp +++ b/src/app/context_flags.cpp @@ -28,7 +28,6 @@ #include "doc/cel.h" #include "doc/layer.h" #include "doc/sprite.h" -#include "doc/stock.h" namespace app { diff --git a/src/app/document.cpp b/src/app/document.cpp index 435da2c16..e8f50c96e 100644 --- a/src/app/document.cpp +++ b/src/app/document.cpp @@ -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(); diff --git a/src/app/document.h b/src/app/document.h index 93b996085..28c79b56d 100644 --- a/src/app/document.h +++ b/src/app/document.h @@ -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. diff --git a/src/app/document_api.cpp b/src/app/document_api.cpp index bb4fb7cc9..3ce20bd66 100644 --- a/src/app/document_api.cpp +++ b/src/app/document_api.cpp @@ -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; cstock()->size(); c++) { - old_image = sprite->stock()->getImage(c); - if (!old_image) - continue; - + std::vector 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::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 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); frametotalFrames(); ++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(new Cel(frameNumber, imageIndex)); + base::UniquePtr 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) diff --git a/src/app/document_api.h b/src/app/document_api.h index cce0872f4..acb6d5aee 100644 --- a/src/app/document_api.h +++ b/src/app/document_api.h @@ -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); diff --git a/src/app/document_exporter.cpp b/src/app/document_exporter.cpp index 8316035f0..e146825af 100644 --- a/src/app/document_exporter.cpp +++ b/src/app/document_exporter.cpp @@ -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" diff --git a/src/app/document_location.cpp b/src/app/document_location.cpp index b37d126b3..5df6145f5 100644 --- a/src/app/document_location.cpp +++ b/src/app/document_location.cpp @@ -25,7 +25,6 @@ #include "doc/cel.h" #include "doc/layer.h" #include "doc/sprite.h" -#include "doc/stock.h" namespace app { diff --git a/src/app/document_range_tests.cpp b/src/app/document_range_tests.cpp index 1fa04a57e..3881dbef3 100644 --- a/src/app/document_range_tests.cpp +++ b/src/app/document_range_tests.cpp @@ -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); } diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index b66372229..c7dab41a9 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -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(new Cel(frame, 0)); + base::UniquePtr 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: { diff --git a/src/app/file/file.cpp b/src/app/file/file.cpp index bc9bf8d32..6f312d2e7 100644 --- a/src/app/file/file.cpp +++ b/src/app/file/file.cpp @@ -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); diff --git a/src/app/file/file.h b/src/app/file/file.h index d6d049f8d..38bab9eb2 100644 --- a/src/app/file/file.h +++ b/src/app/file/file.h @@ -22,6 +22,7 @@ #include "base/shared_ptr.h" #include "doc/frame.h" +#include "doc/image_ref.h" #include "doc/pixel_format.h" #include @@ -95,7 +96,7 @@ namespace app { struct { std::vector 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. diff --git a/src/app/file/fli_format.cpp b/src/app/file/fli_format.cpp index bca4781f2..2c805b5eb 100644 --- a/src/app/file/fli_format.cpp +++ b/src/app/file/fli_format.cpp @@ -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 diff --git a/src/app/file/gif_format.cpp b/src/app/file/gif_format.cpp index f461d0b60..84342be5c 100644 --- a/src/app/file/gif_format.cpp +++ b/src/app/file/gif_format.cpp @@ -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; } diff --git a/src/app/file/gif_tests.cpp b/src/app/file/gif_tests.cpp index 618ce3c49..f04ee5830 100644 --- a/src/app/file/gif_tests.cpp +++ b/src/app/file/gif_tests.cpp @@ -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)); diff --git a/src/app/file/ico_format.cpp b/src/app/file/ico_format.cpp index 1cbc74b27..db036cf8f 100644 --- a/src/app/file/ico_format.cpp +++ b/src/app/file/ico_format.cpp @@ -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); diff --git a/src/app/flatten.cpp b/src/app/flatten.cpp index 50e9c0990..d7d8c4565 100644 --- a/src/app/flatten.cpp +++ b/src/app/flatten.cpp @@ -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 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(new Cel(frame, imageIndex)); + base::UniquePtr cel(new Cel(frame, image)); cel->setPosition(bounds.x, bounds.y); // Render this frame. diff --git a/src/app/ui/color_selector.cpp b/src/app/ui/color_selector.cpp index 45c82f75b..5aebea9ca 100644 --- a/src/app/ui/color_selector.cpp +++ b/src/app/ui/color_selector.cpp @@ -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 images; + sprite->getImages(images); + for (Image* image : images) { const LockImageBits bits(image); for (LockImageBits::const_iterator it=bits.begin(); it!=bits.end(); ++it) { if (lastUsed < *it) diff --git a/src/app/ui/timeline.cpp b/src/app/ui/timeline.cpp index f283675b7..933110464 100644 --- a/src/app/ui/timeline.cpp +++ b/src/app/ui/timeline.cpp @@ -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(layer)->getCel(frame-1): NULL); - Cel* right = (layer->isImage() ? static_cast(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); diff --git a/src/app/undoers/add_image.cpp b/src/app/undoers/add_image.cpp deleted file mode 100644 index d9cfe4b99..000000000 --- a/src/app/undoers/add_image.cpp +++ /dev/null @@ -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(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 diff --git a/src/app/undoers/add_image.h b/src/app/undoers/add_image.h deleted file mode 100644 index c865003e1..000000000 --- a/src/app/undoers/add_image.h +++ /dev/null @@ -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 diff --git a/src/app/undoers/object_io.cpp b/src/app/undoers/object_io.cpp new file mode 100644 index 000000000..90a76068b --- /dev/null +++ b/src/app/undoers/object_io.cpp @@ -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(is, [this](std::istream& is) { + return doc::read_cel(is, this, m_sprite); + }); +} + +Image* ObjectIO::read_image(std::istream& is) +{ + return read_object(is, doc::read_image); +} + +Layer* ObjectIO::read_layer(std::istream& is) +{ + return read_object(is, [this](std::istream& is) { + return doc::read_layer(is, this, m_sprite); + }); +} + +} // namespace undoers +} // namespace app diff --git a/src/app/undoers/object_io.h b/src/app/undoers/object_io.h index 9226eeae8..8f2ce97c6 100644 --- a/src/app/undoers/object_io.h +++ b/src/app/undoers/object_io.h @@ -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 - 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 - 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 object(reader(is)); // Read the object + base::UniquePtr 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 diff --git a/src/app/undoers/remove_cel.cpp b/src/app/undoers/remove_cel.cpp index dfece69bc..8f438c213 100644 --- a/src/app/undoers/remove_cel.cpp +++ b/src/app/undoers/remove_cel.cpp @@ -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(m_layerId); - Cel* cel = read_object(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); diff --git a/src/app/undoers/remove_image.cpp b/src/app/undoers/remove_image.cpp deleted file mode 100644 index 2302e51d0..000000000 --- a/src/app/undoers/remove_image.cpp +++ /dev/null @@ -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(m_stockId); - Image* image = read_object(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 diff --git a/src/app/undoers/remove_image.h b/src/app/undoers/remove_image.h deleted file mode 100644 index 9d2040eda..000000000 --- a/src/app/undoers/remove_image.h +++ /dev/null @@ -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 - -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(&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 diff --git a/src/app/undoers/remove_layer.cpp b/src/app/undoers/remove_layer.cpp index e677bc989..ec906c895 100644 --- a/src/app/undoers/remove_layer.cpp +++ b/src/app/undoers/remove_layer.cpp @@ -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(m_objects, is, doc::read_cel); - } - - Image* read_image(std::istream& is) override { - return read_object(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(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(m_afterId): NULL); // Read the layer from the stream - LayerSubObjectsSerializerImpl serializer(objects, folder->sprite()); - Layer* layer = read_object(objects, m_stream, serializer); + Layer* layer = + ObjectIO(objects, folder->sprite()).read_layer(m_stream); document->getApi(redoers).addLayer(folder, layer, after); } diff --git a/src/app/undoers/replace_image.cpp b/src/app/undoers/replace_image.cpp index 7699b7f63..9056517cd 100644 --- a/src/app/undoers/replace_image.cpp +++ b/src/app/undoers/replace_image.cpp @@ -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(m_stockId); + Sprite* sprite = objects->getObjectT(m_spriteId); + Image* currentImageRaw = objects->getObjectT(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(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 diff --git a/src/app/undoers/replace_image.h b/src/app/undoers/replace_image.h index edee795af..27f3bc6c1 100644 --- a/src/app/undoers/replace_image.h +++ b/src/app/undoers/replace_image.h @@ -26,7 +26,8 @@ #include 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(&m_stream)->tellp(); } - undo::ObjectId m_stockId; - uint32_t m_imageIndex; + undo::ObjectId m_spriteId; + undo::ObjectId m_newImageId; std::stringstream m_stream; }; diff --git a/src/app/util/clipboard.cpp b/src/app/util/clipboard.cpp index a5013f520..abfbf3c2e 100644 --- a/src/app/util/clipboard.cpp +++ b/src/app/util/clipboard.cpp @@ -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" diff --git a/src/app/util/expand_cel_canvas.cpp b/src/app/util/expand_cel_canvas.cpp index 6dd90d7bf..f15ca40e4 100644 --- a/src/app/util/expand_cel_canvas.cpp +++ b/src/app/util/expand_cel_canvas.cpp @@ -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(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(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(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(m_layer)->addCel(m_cel); } + + // And finally we add the cel again in the layer. + static_cast(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(m_layer)->removeCel(m_cel); delete m_cel; - delete m_celImage; + m_celImage.reset(NULL); } m_closed = true; diff --git a/src/app/util/expand_cel_canvas.h b/src/app/util/expand_cel_canvas.h index 52686d87d..590350f37 100644 --- a/src/app/util/expand_cel_canvas.h +++ b/src/app/util/expand_cel_canvas.h @@ -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; diff --git a/src/doc/CMakeLists.txt b/src/doc/CMakeLists.txt index c79303e47..07786a8e6 100644 --- a/src/doc/CMakeLists.txt +++ b/src/doc/CMakeLists.txt @@ -38,5 +38,4 @@ add_library(doc-lib primitives.cpp rgbmap.cpp sprite.cpp - sprites.cpp - stock.cpp) + sprites.cpp) diff --git a/src/doc/cel.cpp b/src/doc/cel.cpp index b1b201b29..933580e53 100644 --- a/src/doc/cel.cpp +++ b/src/doc/cel.cpp @@ -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; frcel(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 diff --git a/src/doc/cel.h b/src/doc/cel.h index 7c4a9fe1b..6f28528c7 100644 --- a/src/doc/cel.h +++ b/src/doc/cel.h @@ -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(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 }; diff --git a/src/doc/cel_io.cpp b/src/doc/cel_io.cpp index 287edb500..9716c5457 100644 --- a/src/doc/cel_io.cpp +++ b/src/doc/cel_io.cpp @@ -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 @@ -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(new Cel(frame, imageIndex)); + base::UniquePtr 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(); } diff --git a/src/doc/cel_io.h b/src/doc/cel_io.h index 46a9757d6..4ced1d81c 100644 --- a/src/doc/cel_io.h +++ b/src/doc/cel_io.h @@ -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 diff --git a/src/doc/doc.h b/src/doc/doc.h index 5b0e76628..d7fc116a8 100644 --- a/src/doc/doc.h +++ b/src/doc/doc.h @@ -27,6 +27,5 @@ #include "doc/primitives_fast.h" #include "doc/rgbmap.h" #include "doc/sprite.h" -#include "doc/stock.h" #endif diff --git a/src/doc/image_ref.h b/src/doc/image_ref.h new file mode 100644 index 000000000..67b1ec128 --- /dev/null +++ b/src/doc/image_ref.h @@ -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 ImageRef; + +} // namespace doc + +#endif diff --git a/src/doc/images_collector.cpp b/src/doc/images_collector.cpp index 98c0b3e75..cd8d8adf7 100644 --- a/src/doc/images_collector.cpp +++ b/src/doc/images_collector.cpp @@ -14,7 +14,6 @@ #include "doc/layer.h" #include "doc/mask.h" #include "doc/sprite.h" -#include "doc/stock.h" namespace doc { diff --git a/src/doc/layer.cpp b/src/doc/layer.cpp index e75cb2152..ae308bf62 100644 --- a/src/doc/layer.cpp +++ b/src/doc/layer.cpp @@ -15,7 +15,6 @@ #include "doc/image.h" #include "doc/primitives.h" #include "doc/sprite.h" -#include "doc/stock.h" #include #include @@ -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) diff --git a/src/doc/layer_io.cpp b/src/doc/layer_io.cpp index 0d3ae95e2..266ec794f 100644 --- a/src/doc/layer_io.cpp +++ b/src/doc/layer_io.cpp @@ -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 #include @@ -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 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(layer.get())->addCel(cel); - - // Read the cel's image - Image* image = subObjects->read_image(is); - - sprite->stock()->replaceImage(cel->imageIndex(), image); } break; } diff --git a/src/doc/layer_io.h b/src/doc/layer_io.h index 2d22f29ee..768f1d16a 100644 --- a/src/doc/layer_io.h +++ b/src/doc/layer_io.h @@ -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 diff --git a/src/doc/object_type.h b/src/doc/object_type.h index ed477a497..d8e945b62 100644 --- a/src/doc/object_type.h +++ b/src/doc/object_type.h @@ -20,7 +20,6 @@ namespace doc { Cel, LayerImage, LayerFolder, - Stock, Sprite, Document, }; diff --git a/src/doc/sprite.cpp b/src/doc/sprite.cpp index 539279a1c..155adaec2 100644 --- a/src/doc/sprite.cpp +++ b/src/doc/sprite.cpp @@ -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 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 cel(new doc::Cel(doc::frame_t(0), indexInStock)); + base::UniquePtr 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; isize(); i++) { - Image* image = m_stock->getImage(i); - if (image != NULL) - image->setMaskColor(color); - } + std::vector images; + getImages(images); + for (Image* image : images) + image->setMaskColor(color); } int Sprite::getMemSize() const { int size = 0; - for (int i=0; isize(); i++) { - Image* image = m_stock->getImage(i); - if (image != NULL) - size += image->getRowStrideSize() * image->height(); - } + std::vector 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& 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& mapping) diff --git a/src/doc/sprite.h b/src/doc/sprite.h index 70bbf49d2..6774e3127 100644 --- a/src/doc/sprite.h +++ b/src/doc/sprite.h @@ -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 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& images) const; void remapImages(frame_t frameFrom, frame_t frameTo, const std::vector& 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 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 diff --git a/src/doc/sprites.cpp b/src/doc/sprites.cpp index b2ec77f74..86947e370 100644 --- a/src/doc/sprites.cpp +++ b/src/doc/sprites.cpp @@ -17,7 +17,6 @@ #include "doc/image.h" #include "doc/layer.h" #include "doc/primitives.h" -#include "doc/stock.h" #include diff --git a/src/doc/stock.cpp b/src/doc/stock.cpp deleted file mode 100644 index a9a1f870a..000000000 --- a/src/doc/stock.cpp +++ /dev/null @@ -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 - -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= 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 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 diff --git a/src/doc/stock.h b/src/doc/stock.h deleted file mode 100644 index 5d8623692..000000000 --- a/src/doc/stock.h +++ /dev/null @@ -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 - -namespace doc { - - class Image; - class Sprite; - - typedef std::vector 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 diff --git a/src/doc/subobjects_io.h b/src/doc/subobjects_io.h new file mode 100644 index 000000000..286ade314 --- /dev/null +++ b/src/doc/subobjects_io.h @@ -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 + +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 diff --git a/src/render/quantization.h b/src/render/quantization.h index 94a5dfc48..04778b1c5 100644 --- a/src/render/quantization.h +++ b/src/render/quantization.h @@ -21,7 +21,6 @@ namespace doc { class Palette; class RgbMap; class Sprite; - class Stock; } namespace render {