Add CelData to share image/position/opacity between linked cels

Changes:
- Merged app::cmd::ObjectIO into doc::SubObjectsIO
- Changed app::cmd::SetCelImage with app::cmd::SetCelData
- Added Cel::createCopy/Link() to avoid confunsion with Cel copy ctor
- Renamed Sprite::getImage() -> getImageRef()
- Added Sprite::getDataCelRef()
- Added doc::CelsRange helper to iterate cels
- Added Sprite::cels()/uniqueCels() member functions (removed
  Sprite::getCels())
- Added DocumentRange::convertToCels()
This commit is contained in:
David Capello 2015-02-09 11:40:43 -03:00
parent e975d1c710
commit 3ebb708000
56 changed files with 992 additions and 548 deletions

View File

@ -43,6 +43,7 @@
# Refactoring
* Replace get_unique_cels() with CelsRange
* Make one level of layers (folders should modify only timeline/UI)
* Convert doc::PixelFormat to a enum class
* Add doc::Spec with width/height/channels/ColorMode/ncolors

View File

@ -75,15 +75,14 @@ add_library(app-lib
cmd/layer_from_background.cpp
cmd/move_cel.cpp
cmd/move_layer.cpp
cmd/object_io.cpp
cmd/remove_cel.cpp
cmd/remove_frame.cpp
cmd/remove_layer.cpp
cmd/remove_palette.cpp
cmd/replace_image.cpp
cmd/reselect_mask.cpp
cmd/set_cel_data.cpp
cmd/set_cel_frame.cpp
cmd/set_cel_image.cpp
cmd/set_cel_opacity.cpp
cmd/set_cel_position.cpp
cmd/set_frame_duration.cpp

View File

@ -22,12 +22,15 @@
#include "app/cmd/add_cel.h"
#include "app/cmd/object_io.h"
#include "base/serialization.h"
#include "doc/cel.h"
#include "doc/cel_io.h"
#include "doc/cel_data_io.h"
#include "doc/document.h"
#include "doc/document_event.h"
#include "doc/image_io.h"
#include "doc/layer.h"
#include "doc/subobjects_io.h"
namespace app {
namespace cmd {
@ -55,13 +58,14 @@ void AddCel::onUndo()
Layer* layer = this->layer();
Cel* cel = this->cel();
// Save the image only if the cel isn't linked
ObjectIO io(layer->sprite());
bool has_image = (cel->links() == 0);
write8(m_stream, has_image ? 1: 0);
if (has_image)
io.write_image(m_stream, cel->image());
io.write_cel(m_stream, cel);
// Save the CelData only if the cel isn't linked
bool has_data = (cel->links() == 0);
write8(m_stream, has_data ? 1: 0);
if (has_data) {
write_image(m_stream, cel->image());
write_celdata(m_stream, cel->data());
}
write_cel(m_stream, cel);
removeCel(layer, cel);
}
@ -70,13 +74,16 @@ void AddCel::onRedo()
{
Layer* layer = this->layer();
ObjectIO io(layer->sprite());
bool has_image = (read8(m_stream) != 0);
if (has_image) {
ImageRef image(io.read_image(m_stream));
io.add_image_ref(image);
SubObjectsIO io(layer->sprite());
bool has_data = (read8(m_stream) != 0);
if (has_data) {
ImageRef image(read_image(m_stream));
io.addImageRef(image);
CelDataRef celdata(read_celdata(m_stream, &io));
io.addCelDataRef(celdata);
}
Cel* cel = io.read_cel(m_stream);
Cel* cel = read_cel(m_stream, &io);
addCel(layer, cel);

View File

@ -22,11 +22,11 @@
#include "app/cmd/add_layer.h"
#include "app/cmd/object_io.h"
#include "doc/layer.h"
#include "doc/document.h"
#include "doc/document_event.h"
#include "doc/layer.h"
#include "doc/layer_io.h"
#include "doc/subobjects_io.h"
namespace app {
namespace cmd {
@ -54,7 +54,7 @@ void AddLayer::onUndo()
Layer* folder = m_folder.layer();
Layer* layer = m_newLayer.layer();
ObjectIO(folder->sprite()).write_layer(m_stream, layer);
write_layer(m_stream, layer);
removeLayer(folder, layer);
}
@ -62,7 +62,8 @@ void AddLayer::onUndo()
void AddLayer::onRedo()
{
Layer* folder = m_folder.layer();
Layer* newLayer = ObjectIO(folder->sprite()).read_layer(m_stream);
SubObjectsIO io(folder->sprite());
Layer* newLayer = read_layer(m_stream, &io);
Layer* afterThis = m_afterThis.layer();
addLayer(folder, newLayer, afterThis);

View File

@ -27,8 +27,7 @@
#include "app/cmd/clear_cel.h"
#include "app/cmd/copy_rect.h"
#include "app/cmd/remove_cel.h"
#include "app/cmd/set_cel_image.h"
#include "app/cmd/set_cel_position.h"
#include "app/cmd/set_cel_data.h"
#include "app/cmd/unlink_cel.h"
#include "app/document.h"
#include "doc/cel.h"
@ -101,8 +100,7 @@ void CopyCel::onExecute()
return;
if (createLink) {
executeAndAdd(new cmd::SetCelImage(dstCel, srcCel->imageRef()));
executeAndAdd(new cmd::SetCelPosition(dstCel, srcCel->x(), srcCel->y()));
executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
}
else {
int blend = (srcLayer->isBackground() ?
@ -121,13 +119,10 @@ void CopyCel::onExecute()
if (srcCel) {
if (createLink)
dstImage = srcSprite->getImage(srcImage->id());
dstCel = Cel::createLink(srcCel);
else
dstImage.reset(Image::createCopy(srcImage));
dstCel = new Cel(*srcCel);
dstCel = Cel::createCopy(srcCel);
dstCel->setFrame(m_dstFrame);
dstCel->setImage(dstImage);
executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
}

View File

@ -70,6 +70,8 @@ void FlattenLayers::onExecute()
clear_image(image, bgcolor);
render.renderSprite(image, sprite, frame);
// TODO Keep cel links when possible
ImageRef cel_image;
Cel* cel = background->cel(frame);
if (cel) {

View File

@ -28,9 +28,8 @@
#include "app/cmd/clear_image.h"
#include "app/cmd/copy_rect.h"
#include "app/cmd/remove_cel.h"
#include "app/cmd/set_cel_data.h"
#include "app/cmd/set_cel_frame.h"
#include "app/cmd/set_cel_image.h"
#include "app/cmd/set_cel_position.h"
#include "app/cmd/unlink_cel.h"
#include "app/document.h"
#include "doc/cel.h"
@ -103,8 +102,7 @@ void MoveCel::onExecute()
return;
if (createLink) {
executeAndAdd(new cmd::SetCelImage(dstCel, srcCel->imageRef()));
executeAndAdd(new cmd::SetCelPosition(dstCel, srcCel->x(), srcCel->y()));
executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
executeAndAdd(new cmd::UnlinkCel(srcCel));
}
else {
@ -129,11 +127,8 @@ void MoveCel::onExecute()
executeAndAdd(new cmd::SetCelFrame(srcCel, m_dstFrame));
}
else {
dstImage.reset(Image::createCopy(srcImage));
dstCel = new Cel(*srcCel);
dstCel = Cel::createCopy(srcCel);
dstCel->setFrame(m_dstFrame);
dstCel->setImage(dstImage);
executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
executeAndAdd(new cmd::ClearCel(srcCel));

View File

@ -1,105 +0,0 @@
/* Aseprite
* Copyright (C) 2001-2015 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/cmd/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 "doc/sprite.h"
namespace app {
namespace cmd {
using namespace doc;
ObjectIO::ObjectIO(Sprite* sprite)
: 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);
});
}
void ObjectIO::add_image_ref(const ImageRef& image)
{
ASSERT(image);
ASSERT(!get_image_ref(image->id()));
m_images.push_back(image);
}
ImageRef ObjectIO::get_image_ref(ObjectId imageId)
{
for (ImageRef& image : m_images) {
if (image->id() == imageId) {
ASSERT(!m_sprite->getImage(imageId));
return image;
}
}
return m_sprite->getImage(imageId);
}
} // namespace cmd
} // namespace app

View File

@ -1,99 +0,0 @@
/* Aseprite
* Copyright (C) 2001-2015 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_CMD_OBJECT_IO_H_INCLUDED
#define APP_CMD_OBJECT_IO_H_INCLUDED
#pragma once
#include "base/serialization.h"
#include "base/unique_ptr.h"
#include "doc/object_id.h"
#include "doc/subobjects_io.h"
namespace doc {
class Cel;
class Image;
class Layer;
class Sprite;
}
namespace app {
namespace cmd {
using namespace doc;
class ObjectIO : public SubObjectsIO {
public:
ObjectIO(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;
void add_image_ref(const ImageRef& image) override;
ImageRef get_image_ref(ObjectId imageId) 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
// same ID which were assigned in the ObjectsContainer previously.
// Serializes the given object into the stream identifying it with an
// 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(std::ostream& os, T* object, Writer writer)
{
using base::serialization::little_endian::write32;
write32(os, object->id()); // Write the ID
writer(os, object); // Write the object
}
// 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(std::istream& is, Reader reader)
{
using base::serialization::little_endian::read32;
doc::ObjectId objectId = read32(is); // Read the ID
base::UniquePtr<T> object(reader(is)); // Read the object
object->setId(objectId);
return object.release();
}
Sprite* m_sprite;
// List of images that can be queried from read_cel() using
// get_image_ref().
std::vector<ImageRef> m_images;
};
} // namespace cmd
} // namespace app
#endif

View File

@ -23,6 +23,7 @@
#include "app/cmd/remove_frame.h"
#include "app/cmd/remove_cel.h"
#include "doc/cels_range.h"
#include "doc/document.h"
#include "doc/document_event.h"
#include "doc/sprite.h"

View File

@ -22,11 +22,11 @@
#include "app/cmd/replace_image.h"
#include "app/cmd/object_io.h"
#include "doc/image.h"
#include "doc/image_io.h"
#include "doc/image_ref.h"
#include "doc/sprite.h"
#include "doc/subobjects_io.h"
namespace app {
namespace cmd {
@ -46,7 +46,7 @@ void ReplaceImage::onExecute()
// Save old image in m_copy. We cannot keep an ImageRef to this
// image, because there are other undo branches that could try to
// modify/re-add this same image ID
ImageRef oldImage = sprite()->getImage(m_oldImageId);
ImageRef oldImage = sprite()->getImageRef(m_oldImageId);
ASSERT(oldImage);
m_copy.reset(Image::createCopy(oldImage));
@ -56,9 +56,9 @@ void ReplaceImage::onExecute()
void ReplaceImage::onUndo()
{
ImageRef newImage = sprite()->getImage(m_newImageId);
ImageRef newImage = sprite()->getImageRef(m_newImageId);
ASSERT(newImage);
ASSERT(!sprite()->getImage(m_oldImageId));
ASSERT(!sprite()->getImageRef(m_oldImageId));
m_copy->setId(m_oldImageId);
sprite()->replaceImage(m_newImageId, m_copy);
@ -67,9 +67,9 @@ void ReplaceImage::onUndo()
void ReplaceImage::onRedo()
{
ImageRef oldImage = sprite()->getImage(m_oldImageId);
ImageRef oldImage = sprite()->getImageRef(m_oldImageId);
ASSERT(oldImage);
ASSERT(!sprite()->getImage(m_newImageId));
ASSERT(!sprite()->getImageRef(m_newImageId));
m_copy->setId(m_newImageId);
sprite()->replaceImage(m_oldImageId, m_copy);

View File

@ -20,71 +20,76 @@
#include "config.h"
#endif
#include "app/cmd/set_cel_image.h"
#include "app/cmd/set_cel_data.h"
#include "app/cmd/object_io.h"
#include "doc/cel.h"
#include "doc/image.h"
#include "doc/image_io.h"
#include "doc/image_ref.h"
#include "doc/sprite.h"
#include "doc/subobjects_io.h"
namespace app {
namespace cmd {
using namespace doc;
SetCelImage::SetCelImage(Cel* cel, const ImageRef& newImage)
SetCelData::SetCelData(Cel* cel, const CelDataRef& newData)
: WithCel(cel)
, m_oldDataId(cel->data()->id())
, m_oldImageId(cel->image()->id())
, m_newImageId(newImage->id())
, m_newImage(newImage)
, m_newDataId(newData->id())
, m_newData(newData)
{
}
void SetCelImage::onExecute()
void SetCelData::onExecute()
{
Cel* cel = this->cel();
if (!cel->links())
createCopy();
if (!cel->links()) {
ImageRef oldImage = cel->imageRef();
m_copy.reset(Image::createCopy(oldImage));
}
cel->setImage(m_newImage);
m_newImage.reset(nullptr);
cel->setDataRef(m_newData);
m_newData.reset(nullptr);
}
void SetCelImage::onUndo()
void SetCelData::onUndo()
{
Cel* cel = this->cel();
if (m_copy) {
ASSERT(!cel->sprite()->getImage(m_oldImageId));
m_copy->setId(m_oldImageId);
cel->setImage(m_copy);
m_copy.reset(nullptr);
if (m_dataCopy) {
ASSERT(!cel->sprite()->getCelDataRef(m_oldDataId));
m_dataCopy->setId(m_oldDataId);
m_dataCopy->image()->setId(m_oldImageId);
cel->setDataRef(m_dataCopy);
m_dataCopy.reset(nullptr);
}
else {
ImageRef oldImage = cel->sprite()->getImage(m_oldImageId);
ASSERT(oldImage);
cel->setImage(oldImage);
CelDataRef oldData = cel->sprite()->getCelDataRef(m_oldDataId);
ASSERT(oldData);
cel->setDataRef(oldData);
}
}
void SetCelImage::onRedo()
void SetCelData::onRedo()
{
Cel* cel = this->cel();
if (!cel->links())
createCopy();
CelDataRef newData = cel->sprite()->getCelDataRef(m_newDataId);
ASSERT(newData);
cel->setDataRef(newData);
}
void SetCelData::createCopy()
{
Cel* cel = this->cel();
if (!cel->links()) {
ImageRef oldImage = cel->imageRef();
m_copy.reset(Image::createCopy(oldImage));
}
ImageRef newImage = cel->sprite()->getImage(m_newImageId);
ASSERT(newImage);
cel->setImage(newImage);
m_newImage.reset(nullptr);
ASSERT(!m_dataCopy);
m_dataCopy.reset(new CelData(*cel->data()));
m_dataCopy->setImage(ImageRef(Image::createCopy(cel->image())));
}
} // namespace cmd

View File

@ -16,13 +16,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_CMD_SET_CEL_IMAGE_H_INCLUDED
#define APP_CMD_SET_CEL_IMAGE_H_INCLUDED
#ifndef APP_CMD_SET_CEL_DATA_H_INCLUDED
#define APP_CMD_SET_CEL_DATA_H_INCLUDED
#pragma once
#include "app/cmd.h"
#include "app/cmd/with_cel.h"
#include "doc/image_ref.h"
#include "doc/cel_data.h"
#include <sstream>
@ -30,10 +30,10 @@ namespace app {
namespace cmd {
using namespace doc;
class SetCelImage : public Cmd
, public WithCel {
class SetCelData : public Cmd
, public WithCel {
public:
SetCelImage(Cel* cel, const ImageRef& newImage);
SetCelData(Cel* cel, const CelDataRef& newData);
protected:
void onExecute() override;
@ -41,18 +41,21 @@ namespace cmd {
void onRedo() override;
size_t onMemSize() const override {
return sizeof(*this) +
(m_copy ? m_copy->getMemSize(): 0);
(m_dataCopy ? m_dataCopy->getMemSize(): 0);
}
private:
ObjectId m_oldImageId;
ObjectId m_newImageId;
void createCopy();
// Reference used only to keep the copy of the new image from the
// SetCelImage() ctor until the SetCelImage::onExecute() call.
ObjectId m_oldDataId;
ObjectId m_oldImageId;
ObjectId m_newDataId;
CelDataRef m_dataCopy;
// Reference used only to keep the copy of the new CelData from
// the SetCelData() ctor until the SetCelData::onExecute() call.
// Then the reference is not used anymore.
ImageRef m_newImage;
ImageRef m_copy;
CelDataRef m_newData;
};
} // namespace cmd

View File

@ -29,6 +29,7 @@
#include "app/document.h"
#include "base/unique_ptr.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/document.h"
#include "doc/layer.h"
#include "doc/palette.h"
@ -80,15 +81,12 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
is_image_from_background));
m_seq.add(new cmd::ReplaceImage(sprite,
sprite->getImage(old_image->id()), new_image));
sprite->getImageRef(old_image->id()), new_image));
}
// Set all cels opacity to 100% if we are converting to indexed.
if (newFormat == IMAGE_INDEXED) {
CelList cels;
sprite->getCels(cels);
for (auto it = cels.begin(), end = cels.end(); it != end; ++it) {
Cel* cel = *it;
for (Cel* cel : sprite->uniqueCels()) {
if (cel->opacity() < 255)
m_seq.add(new cmd::SetCelOpacity(cel, 255));
}

View File

@ -33,8 +33,9 @@ using namespace doc;
UnlinkCel::UnlinkCel(Cel* cel)
: WithCel(cel)
, m_oldLinkedImageId(cel->image()->id())
, m_newLinkedImageId(0)
, m_newImageId(0)
, m_oldCelDataId(cel->dataRef()->id())
, m_newCelDataId(0)
{
ASSERT(cel->links());
}
@ -42,22 +43,32 @@ UnlinkCel::UnlinkCel(Cel* cel)
void UnlinkCel::onExecute()
{
Cel* cel = this->cel();
ImageRef oldImage = cel->sprite()->getImage(m_oldLinkedImageId);
CelDataRef oldCelData = cel->sprite()->getCelDataRef(m_oldCelDataId);
ASSERT(oldCelData);
ImageRef copy(Image::createCopy(oldImage));
if (m_newLinkedImageId)
copy->setId(m_newLinkedImageId);
else
m_newLinkedImageId = copy->id();
ImageRef imgCopy(Image::createCopy(oldCelData->image()));
CelDataRef celDataCopy(new CelData(*oldCelData));
celDataCopy->setImage(imgCopy);
cel->setImage(copy);
if (m_newImageId) {
imgCopy->setId(m_newImageId);
celDataCopy->setId(m_newCelDataId);
}
else {
m_newImageId = imgCopy->id();
m_newCelDataId = celDataCopy->id();
}
cel->setDataRef(celDataCopy);
}
void UnlinkCel::onUndo()
{
Cel* cel = this->cel();
ImageRef oldImage = cel->sprite()->getImage(m_oldLinkedImageId);
cel->setImage(oldImage);
CelDataRef oldCelData = cel->sprite()->getCelDataRef(m_oldCelDataId);
ASSERT(oldCelData);
cel->setDataRef(oldCelData);
}
} // namespace cmd

View File

@ -37,8 +37,9 @@ namespace cmd {
void onUndo() override;
private:
ObjectId m_oldLinkedImageId;
ObjectId m_newLinkedImageId;
ObjectId m_newImageId;
ObjectId m_oldCelDataId;
ObjectId m_newCelDataId;
};
} // namespace cmd

View File

@ -36,6 +36,7 @@
#include "app/util/range_utils.h"
#include "doc/algorithm/flip_image.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/mask.h"
@ -92,15 +93,13 @@ void FlipCommand::onExecute(Context* context)
DocumentLocation loc = *writer.location();
DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range();
if (range.enabled())
cels = get_cels_in_range(sprite, range);
cels = get_unique_cels(sprite, range);
else if (writer.cel())
cels.push_back(writer.cel());
for (Cel* cel : cels) {
loc.frame(cel->frame());
loc.layer(cel->layer());
if (cel->link())
continue;
int x, y;
Image* image = loc.image(&x, &y);
@ -154,13 +153,7 @@ void FlipCommand::onExecute(Context* context)
}
}
else {
// get all sprite cels
CelList cels;
sprite->getCels(cels);
// for each cel...
for (CelIterator it = cels.begin(); it != cels.end(); ++it) {
Cel* cel = *it;
for (Cel* cel : sprite->uniqueCels()) {
Image* image = cel->image();
api.setCelPosition
@ -172,8 +165,7 @@ void FlipCommand::onExecute(Context* context)
sprite->height() - image->height() - cel->y():
cel->y()));
if (!cel->link())
api.flipImage(image, image->bounds(), m_flipType);
api.flipImage(image, image->bounds(), m_flipType);
}
}

View File

@ -28,13 +28,14 @@
#include "app/document_range.h"
#include "app/job.h"
#include "app/modules/gui.h"
#include "app/transaction.h"
#include "app/ui/color_bar.h"
#include "app/ui/main_window.h"
#include "app/ui/timeline.h"
#include "app/transaction.h"
#include "app/util/range_utils.h"
#include "base/convert_to.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/image.h"
#include "doc/mask.h"
#include "doc/sprite.h"
@ -82,9 +83,7 @@ public:
protected:
/**
* [working thread]
*/
// [working thread]
virtual void onJob()
{
Transaction transaction(m_writer.context(), "Rotate Canvas");
@ -119,7 +118,7 @@ protected:
int i = 0;
for (Cel* cel : m_cels) {
Image* image = cel->image();
if (image && !cel->link()) {
if (image) {
ImageRef new_image(Image::create(image->pixelFormat(),
m_angle == 180 ? image->width(): image->height(),
m_angle == 180 ? image->height(): image->width()));
@ -219,13 +218,15 @@ void RotateCommand::onExecute(Context* context)
if (m_flipMask) {
DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range();
if (range.enabled())
cels = get_cels_in_range(reader.sprite(), range);
cels = get_unique_cels(reader.sprite(), range);
else if (reader.cel())
cels.push_back(reader.cel());
}
// Flip the whole sprite
else if (reader.sprite()) {
reader.sprite()->getCels(cels);
for (Cel* cel : reader.sprite()->uniqueCels())
cels.push_back(cel);
rotateSprite = true;
}

View File

@ -31,12 +31,13 @@
#include "app/load_widget.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/ui_context.h"
#include "app/transaction.h"
#include "app/ui_context.h"
#include "base/bind.h"
#include "base/unique_ptr.h"
#include "doc/algorithm/resize_image.h"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/image.h"
#include "doc/mask.h"
#include "doc/primitives.h"
@ -84,15 +85,13 @@ protected:
Transaction transaction(m_writer.context(), "Sprite Size");
DocumentApi api = m_writer.document()->getApi(transaction);
// Get all sprite cels
CelList cels;
m_sprite->getCels(cels);
int cels_count = 0;
for (Cel* cel : m_sprite->uniqueCels())
++cels_count;
// For each cel...
int progress = 0;
for (CelIterator it = cels.begin(); it != cels.end(); ++it, ++progress) {
Cel* cel = *it;
for (Cel* cel : m_sprite->uniqueCels()) {
// Change its location
api.setCelPosition(m_sprite, cel, scale_x(cel->x()), scale_y(cel->y()));
@ -113,7 +112,8 @@ protected:
api.replaceImage(m_sprite, cel->imageRef(), new_image);
}
jobProgress((float)progress / cels.size());
jobProgress((float)progress / cels_count);
++progress;
// cancel all the operation?
if (isCanceled())

View File

@ -42,6 +42,7 @@
#include <cstdlib>
#include <cstring>
#include <set>
namespace app {
@ -225,20 +226,21 @@ void FilterManagerImpl::applyToTarget()
m_progressBase = 0.0f;
m_progressWidth = 1.0f / images.size();
std::set<ObjectId> visited;
// For each target image
for (auto it = images.begin();
it != images.end() && !cancelled;
++it) {
Image* image = it->image();
if (it->cel()->links() && images.size() > 1) {
transaction.execute(new cmd::UnlinkCel(it->cel()));
image = it->cel()->image();
// Avoid applying the filter two times to the same image
if (visited.find(image->id()) == visited.end()) {
visited.insert(image->id());
applyToImage(transaction, it->layer(),
image, it->cel()->x(), it->cel()->y());
}
applyToImage(transaction, it->layer(),
image, it->cel()->x(), it->cel()->y());
// Is there a delegate to know if the process was cancelled by the user?
if (m_progressDelegate)
cancelled = m_progressDelegate->isCancelled();

View File

@ -357,6 +357,7 @@ void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, La
{
// Copy the layer name
destLayer0->setName(sourceLayer0->name());
destLayer0->setFlags(sourceLayer0->flags());
if (sourceLayer0->isImage() && destLayer0->isImage()) {
const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
@ -366,26 +367,23 @@ void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, La
CelConstIterator it = sourceLayer->getCelBegin();
CelConstIterator end = sourceLayer->getCelEnd();
std::map<ObjectId, ImageRef> linkedImages;
std::map<ObjectId, Cel*> linked;
for (; it != end; ++it) {
const Cel* sourceCel = *it;
if (sourceCel->frame() > destLayer->sprite()->lastFrame())
break;
base::UniquePtr<Cel> newCel(new Cel(*sourceCel));
base::UniquePtr<Cel> newCel;
const Image* sourceImage = sourceCel->image();
ASSERT(sourceImage != NULL);
auto it = linkedImages.find(sourceImage->id());
if (it != linkedImages.end()) {
newCel->setImage(it->second);
auto it = linked.find(sourceCel->data()->id());
if (it != linked.end()) {
newCel.reset(Cel::createLink(it->second));
newCel->setFrame(sourceCel->frame());
}
else {
ImageRef newImage(Image::createCopy(sourceImage));
newCel->setImage(newImage);
linkedImages.insert(std::make_pair(sourceImage->id(), newImage));
newCel.reset(Cel::createCopy(sourceCel));
linked.insert(std::make_pair(sourceCel->data()->id(), newCel.get()));
}
destLayer->addCel(newCel);

View File

@ -65,6 +65,8 @@
#include "render/quantization.h"
#include "render/render.h"
#include <set>
namespace app {
DocumentApi::DocumentApi(Document* document, Transaction& transaction)
@ -94,10 +96,14 @@ void DocumentApi::cropSprite(Sprite* sprite, const gfx::Rect& bounds)
if (!layer->isImage())
continue;
std::set<ObjectId> visited;
CelIterator it = ((LayerImage*)layer)->getCelBegin();
CelIterator end = ((LayerImage*)layer)->getCelEnd();
for (; it != end; ++it) {
Cel* cel = *it;
if (visited.find(cel->data()->id()) != visited.end())
continue;
visited.insert(cel->data()->id());
if (layer->isBackground()) {
Image* image = cel->image();
@ -260,7 +266,7 @@ void DocumentApi::moveFrameLayer(Layer* layer, frame_t frame, frame_t beforeFram
frame_t celFrame = cel->frame();
frame_t newFrame = celFrame;
// fthe frame to the future
// moving the frame to the future
if (frame < beforeFrame) {
if (celFrame == frame) {
newFrame = beforeFrame-1;

View File

@ -22,10 +22,33 @@
#include "app/document_range.h"
#include "doc/cel.h"
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/sprite.h"
namespace app {
using namespace doc;
DocumentRange::DocumentRange()
: m_type(kNone)
, m_layerBegin(0)
, m_layerEnd(-1)
, m_frameBegin(0)
, m_frameEnd(-1)
{
}
DocumentRange::DocumentRange(Cel* cel)
: m_type(kCels)
, m_layerBegin(cel->sprite()->layerToIndex(cel->layer()))
, m_layerEnd(m_layerBegin)
, m_frameBegin(cel->frame())
, m_frameEnd(m_frameBegin)
{
}
void DocumentRange::startRange(LayerIndex layer, frame_t frame, Type type)
{
m_type = type;
@ -88,4 +111,25 @@ void DocumentRange::displace(int layerDelta, int frameDelta)
m_frameEnd += frame_t(frameDelta);
}
bool DocumentRange::convertToCels(Sprite* sprite)
{
switch (m_type) {
case DocumentRange::kNone:
return false;
case DocumentRange::kCels:
break;
case DocumentRange::kFrames:
m_layerBegin = sprite->firstLayer();
m_layerEnd = sprite->lastLayer();
m_type = DocumentRange::kCels;
break;
case DocumentRange::kLayers:
m_frameBegin = frame_t(0);
m_frameEnd = sprite->lastFrame();
m_type = DocumentRange::kCels;
break;
}
return true;
}
} // namespace app

View File

@ -25,6 +25,11 @@
#include <algorithm>
namespace doc {
class Cel;
class Sprite;
}
namespace app {
using namespace doc;
@ -32,7 +37,8 @@ namespace app {
public:
enum Type { kNone, kCels, kFrames, kLayers };
DocumentRange() : m_type(kNone) { }
DocumentRange();
DocumentRange(Cel* cel);
Type type() const { return m_type; }
bool enabled() const { return m_type != kNone; }
@ -61,6 +67,8 @@ namespace app {
frameBegin() == o.frameBegin() && frameEnd() == o.frameEnd();
}
bool convertToCels(Sprite* sprite);
private:
Type m_type;
LayerIndex m_layerBegin;

View File

@ -172,9 +172,12 @@ protected:
bool expect_cel(int expected_layer, int expected_frame, int layer, frame_t frame) {
color_t expected_color = white;
Cel* cel = sprite->indexToLayer(LayerIndex(layer))->cel(frame);
if (!cel)
return false;
color_t color = get_pixel(
sprite->indexToLayer(LayerIndex(layer))
->cel(frame)->image(),
cel->image(),
expected_layer, expected_frame);
EXPECT_EQ(expected_color, color);

View File

@ -1020,9 +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, ImageRef(NULL)));
cel->setPosition(x, y);
cel->setOpacity(opacity);
base::UniquePtr<Cel> cel;
switch (cel_type) {
@ -1050,7 +1048,9 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
break;
}
cel->setImage(image);
cel.reset(new Cel(frame, image));
cel->setPosition(x, y);
cel->setOpacity(opacity);
}
break;
}
@ -1061,12 +1061,19 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
Cel* link = layer->cel(link_frame);
if (link) {
#if 0 // Create a copy of the linked cel (avoid using links cel)
ImageRef image(Image::createCopy(link->image()));
cel->setImage(image);
#else // Use linked cels
cel->setImage(link->imageRef());
#endif
// There were a beta version that allow to the user specify
// different X, Y, or opacity per link, in that case we must
// create a copy.
if (link->x() == x && link->y() == y && link->opacity() == opacity) {
cel.reset(Cel::createLink(link));
cel->setFrame(frame);
}
else {
cel.reset(Cel::createCopy(link));
cel->setFrame(frame);
cel->setPosition(x, y);
cel->setOpacity(opacity);
}
}
else {
// Linked cel doesn't found
@ -1106,16 +1113,20 @@ static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame,
fop_error(fop, e.what());
}
cel->setImage(image);
cel.reset(new Cel(frame, image));
cel->setPosition(x, y);
cel->setOpacity(opacity);
}
break;
}
}
Cel* newCel = cel.release();
static_cast<LayerImage*>(layer)->addCel(newCel);
return newCel;
if (!cel)
return nullptr;
static_cast<LayerImage*>(layer)->addCel(cel);
return cel.release();
}
static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, Cel* cel, LayerImage* layer, Sprite* sprite)

View File

@ -466,7 +466,7 @@ void fop_operate(FileOp *fop, IFileOpProgress* progress)
// TODO set_palette for each frame???
#define SEQUENCE_IMAGE() \
do { \
fop->seq.last_cel->setImage(fop->seq.image); \
fop->seq.last_cel->data()->setImage(fop->seq.image); \
fop->seq.layer->addCel(fop->seq.last_cel); \
\
if (fop->document->sprite()->palette(frame) \

View File

@ -462,7 +462,7 @@ bool GifFormat::onPostLoad(FileOp* fop)
try {
// Add the image in the sprite's stock and update the cel's
// reference to the new stock's image.
cel->setImage(cel_image);
cel->data()->setImage(cel_image);
}
catch (...) {
throw;

View File

@ -95,17 +95,16 @@ bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg)
gfx::Point delta = m_celNew - m_celStart;
DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range();
if (range.enabled()) {
for (Cel* cel : get_cels_in_range(writer.sprite(), range)) {
Layer* layer = cel->layer();
ASSERT(layer);
if (layer && layer->isMovable() && !layer->isBackground())
api.setCelPosition(writer.sprite(), cel, cel->x()+delta.x, cel->y()+delta.y);
if (!range.enabled())
range = DocumentRange(m_cel);
for (Cel* cel : get_unique_cels(writer.sprite(), range)) {
Layer* layer = cel->layer();
ASSERT(layer);
if (layer && layer->isMovable() && !layer->isBackground()) {
api.setCelPosition(writer.sprite(), cel, cel->x()+delta.x, cel->y()+delta.y);
}
}
else if (m_cel) {
api.setCelPosition(writer.sprite(), m_cel, m_celNew.x, m_celNew.y);
}
// Move selection if it was visible
if (m_maskVisible)

View File

@ -580,7 +580,7 @@ static void slider_change_hook(Slider* slider)
DocumentRange range = App::instance()->getMainWindow()->getTimeline()->range();
if (range.enabled()) {
for (Cel* cel : get_cels_in_range(writer.sprite(), range))
for (Cel* cel : get_unique_cels(writer.sprite(), range))
cel->setOpacity(slider->getValue());
}
else {

View File

@ -24,13 +24,14 @@
#include "app/app.h"
#include "app/cmd/add_cel.h"
#include "app/cmd/copy_region.h"
#include "app/cmd/replace_image.h"
#include "app/cmd/set_cel_position.h"
#include "app/cmd/copy_region.h"
#include "app/context.h"
#include "app/document.h"
#include "app/document_location.h"
#include "app/transaction.h"
#include "app/util/range_utils.h"
#include "base/unique_ptr.h"
#include "doc/cel.h"
#include "doc/image.h"
@ -153,7 +154,7 @@ void ExpandCelCanvas::commit()
// Add a copy of m_dstImage in the sprite's image stock
ImageRef newImage(Image::createCopy(m_dstImage));
m_cel->setImage(newImage);
m_cel->data()->setImage(newImage);
// And finally we add the cel again in the layer.
m_transaction.execute(new cmd::AddCel(m_layer, m_cel));
@ -183,8 +184,7 @@ void ExpandCelCanvas::commit()
if (m_cel->position() != m_origCelPos) {
gfx::Point newPos = m_cel->position();
m_cel->setPosition(m_origCelPos);
m_transaction.execute(new cmd::SetCelPosition(m_cel,
newPos.x, newPos.y));
m_transaction.execute(new cmd::SetCelPosition(m_cel, newPos.x, newPos.y));
}
// Validate the whole m_dstImage copying invalid areas from m_celImage

View File

@ -20,36 +20,30 @@
#include "config.h"
#endif
#include "app/util/range_utils.h"
#include "app/context_access.h"
#include "app/document.h"
#include "app/document_range.h"
#include "doc/cel.h"
#include "doc/layer.h"
#include "doc/sprite.h"
#include <set>
namespace app {
using namespace doc;
// TODO the DocumentRange should be "iteratable" to replace this function
CelList get_cels_in_range(Sprite* sprite, const DocumentRange& inrange)
CelList get_unique_cels(Sprite* sprite, const DocumentRange& inrange)
{
DocumentRange range = inrange;
CelList cels;
if (!range.convertToCels(sprite))
return cels;
switch (range.type()) {
case DocumentRange::kNone:
return cels;
case DocumentRange::kCels:
break;
case DocumentRange::kFrames:
range.startRange(LayerIndex(0), inrange.frameBegin(), DocumentRange::kCels);
range.endRange(LayerIndex(sprite->countLayers()-1), inrange.frameEnd());
break;
case DocumentRange::kLayers:
range.startRange(inrange.layerBegin(), frame_t(0), DocumentRange::kCels);
range.endRange(inrange.layerEnd(), sprite->lastFrame());
break;
}
std::set<ObjectId> visited;
for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
Layer* layer = sprite->indexToLayer(layerIdx);
@ -62,8 +56,13 @@ CelList get_cels_in_range(Sprite* sprite, const DocumentRange& inrange)
frame != begin;
--frame) {
Cel* cel = layerImage->cel(frame);
if (cel)
if (!cel)
continue;
if (visited.find(cel->data()->id()) == visited.end()) {
visited.insert(cel->data()->id());
cels.push_back(cel);
}
}
}
return cels;

View File

@ -20,14 +20,20 @@
#define APP_UTIL_RANGE_UTILS_H_INCLUDED
#pragma once
#include "doc/object.h"
#include "doc/cel_list.h"
#include <vector>
namespace doc {
class Sprite;
}
namespace app {
using namespace doc;
class DocumentRange;
CelList get_cels_in_range(doc::Sprite* sprite, const DocumentRange& range);
doc::CelList get_unique_cels(doc::Sprite* sprite, const DocumentRange& range);
} // namespace app

View File

@ -13,7 +13,10 @@ add_library(doc-lib
blend.cpp
brush.cpp
cel.cpp
cel_data.cpp
cel_data_io.cpp
cel_io.cpp
cels_range.cpp
color_scales.cpp
context.cpp
conversion_she.cpp
@ -36,4 +39,5 @@ add_library(doc-lib
primitives.cpp
rgbmap.cpp
sprite.cpp
sprites.cpp)
sprites.cpp
subobjects_io.cpp)

View File

@ -1,4 +1,4 @@
Copyright (c) 2001-2014 David Capello
Copyright (c) 2001-2015 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -1,4 +1,4 @@
# Aseprite Document Library
*Copyright (C) 2001-2014 David Capello*
*Copyright (C) 2001-2015 David Capello*
> Distributed under [MIT license](LICENSE.txt)

View File

@ -21,24 +21,33 @@ Cel::Cel(frame_t frame, const ImageRef& image)
: Object(ObjectType::Cel)
, m_layer(NULL)
, m_frame(frame)
, m_image(image)
, m_position(0, 0)
, m_opacity(255)
, m_data(new CelData(image))
{
}
Cel::Cel(const Cel& cel)
Cel::Cel(frame_t frame, const CelDataRef& celData)
: Object(ObjectType::Cel)
, m_layer(NULL)
, m_frame(cel.m_frame)
, m_image(cel.m_image)
, m_position(cel.m_position)
, m_opacity(cel.m_opacity)
, m_frame(frame)
, m_data(celData)
{
}
Cel::~Cel()
// static
Cel* Cel::createCopy(const Cel* other)
{
Cel* cel = new Cel(other->frame(),
ImageRef(Image::createCopy(other->image())));
cel->setPosition(other->position());
cel->setOpacity(other->opacity());
return cel;
}
// static
Cel* Cel::createLink(const Cel* other)
{
return new Cel(other->frame(), other->dataRef());
}
void Cel::setFrame(frame_t frame)
@ -47,12 +56,25 @@ void Cel::setFrame(frame_t frame)
m_frame = frame;
}
void Cel::setImage(const ImageRef& image)
void Cel::setDataRef(const CelDataRef& celData)
{
ASSERT(image.get());
ASSERT(celData);
m_data = celData;
}
m_image = image;
fixupImage();
void Cel::setPosition(int x, int y)
{
setPosition(gfx::Point(x, y));
}
void Cel::setPosition(const gfx::Point& pos)
{
m_data->setPosition(pos);
}
void Cel::setOpacity(int opacity)
{
m_data->setOpacity(opacity);
}
Document* Cel::document() const
@ -75,13 +97,14 @@ Sprite* Cel::sprite() const
Cel* Cel::link() const
{
if (m_image.get() == NULL)
ASSERT(m_data);
if (m_data.get() == NULL)
return NULL;
if (!m_image.unique()) {
if (!m_data.unique()) {
for (frame_t fr=0; fr<m_frame; ++fr) {
Cel* possible = m_layer->cel(fr);
if (possible && possible->imageRef().get() == m_image.get())
if (possible && possible->dataRef().get() == m_data.get())
return possible;
}
}
@ -96,7 +119,7 @@ size_t Cel::links() const
Sprite* sprite = this->sprite();
for (frame_t fr=0; fr<sprite->totalFrames(); ++fr) {
Cel* cel = m_layer->cel(fr);
if (cel && cel != this && cel->imageRef().get() == m_image.get())
if (cel && cel != this && cel->dataRef().get() == m_data.get())
++links;
}
@ -109,7 +132,7 @@ gfx::Rect Cel::bounds() const
ASSERT(image);
if (image)
return gfx::Rect(
m_position.x, m_position.y,
position().x, position().y,
image->width(), image->height());
else
return gfx::Rect();
@ -124,8 +147,8 @@ void Cel::setParentLayer(LayerImage* layer)
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());
if (m_layer && image())
image()->setMaskColor(m_layer->sprite()->transparentColor());
}
} // namespace doc

View File

@ -8,6 +8,8 @@
#define DOC_CEL_H_INCLUDED
#pragma once
#include "base/disable_copying.h"
#include "doc/cel_data.h"
#include "doc/frame.h"
#include "doc/image_ref.h"
#include "doc/object.h"
@ -23,18 +25,22 @@ namespace doc {
class Cel : public Object {
public:
Cel(frame_t frame, const ImageRef& image);
Cel(const Cel& cel);
virtual ~Cel();
Cel(frame_t frame, const CelDataRef& celData);
static Cel* createCopy(const Cel* other);
static Cel* createLink(const Cel* other);
frame_t frame() const { return m_frame; }
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; }
int x() const { return m_data->position().x; }
int y() const { return m_data->position().y; }
gfx::Point position() const { return m_data->position(); }
int opacity() const { return m_data->opacity(); }
LayerImage* layer() const { return m_layer; }
Image* image() const { return const_cast<Image*>(m_image.get()); };
ImageRef imageRef() const { return m_image; }
Image* image() const { return m_data->image(); }
ImageRef imageRef() const { return m_data->imageRef(); }
CelData* data() const { return const_cast<CelData*>(m_data.get()); }
CelDataRef dataRef() const { return m_data; }
Document* document() const;
Sprite* sprite() const;
Cel* link() const;
@ -42,19 +48,16 @@ namespace doc {
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
// layer. If the cel is already in a layer, you should use
// LayerImage::moveCel() member function.
void setFrame(frame_t frame);
void setImage(const ImageRef& image);
void setPosition(int x, int y) {
m_position.x = x;
m_position.y = y;
}
void setPosition(const gfx::Point& pos) { m_position = pos; }
void setOpacity(int opacity) { m_opacity = opacity; }
void setDataRef(const CelDataRef& celData);
void setPosition(int x, int y);
void setPosition(const gfx::Point& pos);
void setOpacity(int opacity);
virtual int getMemSize() const override {
return sizeof(Cel);
return sizeof(Cel) + m_data->getMemSize();
}
void setParentLayer(LayerImage* layer);
@ -64,9 +67,10 @@ namespace doc {
LayerImage* m_layer;
frame_t m_frame; // Frame position
ImageRef m_image;
gfx::Point m_position; // X/Y screen position
int m_opacity; // Opacity level
CelDataRef m_data;
Cel();
DISABLE_COPYING(Cel);
};
} // namespace doc

43
src/doc/cel_data.cpp Normal file
View File

@ -0,0 +1,43 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 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/cel_data.h"
#include "gfx/rect.h"
#include "doc/image.h"
#include "doc/layer.h"
#include "doc/sprite.h"
namespace doc {
CelData::CelData(const ImageRef& image)
: Object(ObjectType::CelData)
, m_image(image)
, m_position(0, 0)
, m_opacity(255)
{
}
CelData::CelData(const CelData& celData)
: Object(ObjectType::CelData)
, m_image(celData.m_image)
, m_position(celData.m_position)
, m_opacity(celData.m_opacity)
{
}
void CelData::setImage(const ImageRef& image)
{
ASSERT(image.get());
m_image = image;
}
} // namespace doc

50
src/doc/cel_data.h Normal file
View File

@ -0,0 +1,50 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_CEL_DATA_H_INCLUDED
#define DOC_CEL_DATA_H_INCLUDED
#pragma once
#include "base/shared_ptr.h"
#include "doc/image_ref.h"
#include "doc/object.h"
namespace doc {
class CelData : public Object {
public:
CelData(const ImageRef& image);
CelData(const CelData& celData);
const gfx::Point& position() const { return m_position; }
int opacity() const { return m_opacity; }
Image* image() const { return const_cast<Image*>(m_image.get()); };
ImageRef imageRef() const { return m_image; }
void setImage(const ImageRef& image);
void setPosition(int x, int y) {
m_position.x = x;
m_position.y = y;
}
void setPosition(const gfx::Point& pos) { m_position = pos; }
void setOpacity(int opacity) { m_opacity = opacity; }
virtual int getMemSize() const override {
ASSERT(m_image);
return sizeof(CelData) + m_image->getMemSize();
}
private:
ImageRef m_image;
gfx::Point m_position; // X/Y screen position
int m_opacity; // Opacity level
};
typedef SharedPtr<CelData> CelDataRef;
} // namespace doc
#endif

51
src/doc/cel_data_io.cpp Normal file
View File

@ -0,0 +1,51 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 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/cel_data_io.h"
#include "base/serialization.h"
#include "base/unique_ptr.h"
#include "doc/cel_data.h"
#include "doc/subobjects_io.h"
#include <iostream>
namespace doc {
using namespace base::serialization;
using namespace base::serialization::little_endian;
void write_celdata(std::ostream& os, CelData* celdata)
{
write32(os, celdata->id());
write16(os, (int16_t)celdata->position().x);
write16(os, (int16_t)celdata->position().y);
write8(os, celdata->opacity());
write32(os, celdata->image()->id());
}
CelData* read_celdata(std::istream& is, SubObjectsIO* subObjects)
{
ObjectId id = read32(is);
int x = (int16_t)read16(is);
int y = (int16_t)read16(is);
int opacity = read8(is);
ObjectId imageId = read32(is);
ImageRef image(subObjects->getImageRef(imageId));
base::UniquePtr<CelData> celdata(new CelData(image));
celdata->setPosition(x, y);
celdata->setOpacity(opacity);
celdata->setId(id);
return celdata.release();
}
}

23
src/doc/cel_data_io.h Normal file
View File

@ -0,0 +1,23 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_CEL_DATA_IO_H_INCLUDED
#define DOC_CEL_DATA_IO_H_INCLUDED
#pragma once
#include <iosfwd>
namespace doc {
class CelData;
class SubObjectsIO;
void write_celdata(std::ostream& os, CelData* cel);
CelData* read_celdata(std::istream& is, SubObjectsIO* subObjects);
} // namespace doc
#endif

View File

@ -13,7 +13,6 @@
#include "base/serialization.h"
#include "base/unique_ptr.h"
#include "doc/cel.h"
#include "doc/sprite.h"
#include "doc/subobjects_io.h"
#include <iostream>
@ -23,29 +22,23 @@ namespace doc {
using namespace base::serialization;
using namespace base::serialization::little_endian;
void write_cel(std::ostream& os, SubObjectsIO* subObjects, Cel* cel)
void write_cel(std::ostream& os, Cel* cel)
{
write32(os, cel->id());
write16(os, cel->frame());
write16(os, (int16_t)cel->x());
write16(os, (int16_t)cel->y());
write8(os, cel->opacity());
write32(os, cel->image()->id());
write32(os, cel->dataRef()->id());
}
Cel* read_cel(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
Cel* read_cel(std::istream& is, SubObjectsIO* subObjects)
{
ObjectId id = read32(is);
frame_t frame(read16(is));
int x = (int16_t)read16(is);
int y = (int16_t)read16(is);
int opacity = read8(is);
base::UniquePtr<Cel> cel(new Cel(frame, ImageRef(NULL)));
cel->setPosition(x, y);
cel->setOpacity(opacity);
ObjectId imageId = read32(is);
cel->setImage(subObjects->get_image_ref(imageId));
ObjectId celDataId = read32(is);
CelDataRef celData(subObjects->getCelDataRef(celDataId));
ASSERT(celData);
base::UniquePtr<Cel> cel(new Cel(frame, celData));
cel->setId(id);
return cel.release();
}

View File

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

84
src/doc/cels_range.cpp Normal file
View File

@ -0,0 +1,84 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 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/cels_range.h"
#include "doc/cel.h"
#include "doc/layer.h"
#include "doc/sprite.h"
namespace doc {
CelsRange::CelsRange(const Sprite* sprite,
frame_t first, frame_t last, Flags flags)
: m_begin(sprite, first, last, flags)
, m_end()
{
}
CelsRange::iterator::iterator()
: m_cel(nullptr)
{
}
CelsRange::iterator::iterator(const Sprite* sprite, frame_t first, frame_t last, CelsRange::Flags flags)
: m_cel(nullptr)
, m_first(first)
, m_last(last)
, m_flags(flags)
{
// Get first cel
Layer* layer = sprite->layer(sprite->firstLayer());
while (layer && !m_cel) {
for (frame_t f=first; f<=last; ++f) {
m_cel = layer->cel(f);
if (m_cel)
break;
m_cel = nullptr;
}
layer = layer->getNext();
}
if (m_cel && flags == CelsRange::UNIQUE)
m_visited.insert(m_cel->data()->id());
}
CelsRange::iterator& CelsRange::iterator::operator++()
{
if (!m_cel)
return *this;
// Get next cel
Layer* layer = m_cel->layer();
frame_t first = m_cel->frame()+1;
m_cel = nullptr;
while (layer && !m_cel) {
for (frame_t f=first; f<=m_last; ++f) {
m_cel = layer->cel(f);
if (m_cel) {
if (m_flags == CelsRange::UNIQUE) {
if (m_visited.find(m_cel->data()->id()) == m_visited.end()) {
m_visited.insert(m_cel->data()->id());
break;
}
else
m_cel = nullptr;
}
else
break;
}
}
layer = layer->getNext();
first = m_first;
}
return *this;
}
} // namespace doc

66
src/doc/cels_range.h Normal file
View File

@ -0,0 +1,66 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef DOC_CELS_RANGE_H_INCLUDED
#define DOC_CELS_RANGE_H_INCLUDED
#pragma once
#include "doc/frame.h"
#include "doc/object_id.h"
#include <set>
namespace doc {
class Cel;
class Sprite;
class CelsRange {
public:
enum Flags {
ALL,
UNIQUE,
};
CelsRange(const Sprite* sprite,
frame_t first, frame_t last, Flags flags = ALL);
class iterator {
public:
iterator();
iterator(const Sprite* sprite, frame_t first, frame_t last, Flags flags);
bool operator==(const iterator& other) const {
return m_cel == other.m_cel;
}
bool operator!=(const iterator& other) const {
return !operator==(other);
}
Cel* operator*() const {
return m_cel;
}
iterator& operator++();
private:
Cel* m_cel;
frame_t m_first, m_last;
Flags m_flags;
std::set<ObjectId> m_visited;
};
iterator begin() { return m_begin; }
iterator end() { return m_end; }
private:
iterator m_begin, m_end;
Flags m_flags;
};
} // namespace doc
#endif

View File

@ -35,6 +35,7 @@ using namespace base::serialization::little_endian;
void write_image(std::ostream& os, Image* image)
{
write32(os, image->id());
write8(os, image->pixelFormat()); // Pixel format
write16(os, image->width()); // Width
write16(os, image->height()); // Height
@ -47,6 +48,7 @@ void write_image(std::ostream& os, Image* image)
Image* read_image(std::istream& is)
{
ObjectId id = read32(is);
int pixelFormat = read8(is); // Pixel format
int width = read16(is); // Width
int height = read16(is); // Height
@ -59,6 +61,7 @@ Image* read_image(std::istream& is)
is.read((char*)image->getPixelAddress(0, c), size);
image->setMaskColor(maskColor);
image->setId(id);
return image.release();
}

View File

@ -153,8 +153,10 @@ Cel* LayerImage::getLastCel() const
return NULL;
}
void LayerImage::addCel(Cel *cel)
void LayerImage::addCel(Cel* cel)
{
ASSERT(cel->data() && "The cel doesn't contain CelData");
CelIterator it = getCelBegin();
CelIterator end = getCelEnd();

View File

@ -13,7 +13,12 @@
#include "base/serialization.h"
#include "base/unique_ptr.h"
#include "doc/cel.h"
#include "doc/cel_data.h"
#include "doc/cel_data_io.h"
#include "doc/cel_io.h"
#include "doc/image_io.h"
#include "doc/layer.h"
#include "doc/layer_io.h"
#include "doc/sprite.h"
#include "doc/subobjects_io.h"
@ -27,10 +32,12 @@ using namespace base::serialization::little_endian;
// Serialized Layer data:
void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer)
void write_layer(std::ostream& os, Layer* layer)
{
std::string name = layer->name();
write32(os, layer->id());
write16(os, name.size()); // Name length
if (!name.empty())
os.write(name.c_str(), name.size()); // Name
@ -46,23 +53,34 @@ void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer)
// Images
int images = 0;
int celdatas = 0;
for (it=begin; it != end; ++it) {
Cel* cel = *it;
if (!cel->link())
if (!cel->link()) {
++images;
++celdatas;
}
}
write16(os, images);
for (it=begin; it != end; ++it) {
Cel* cel = *it;
if (!cel->link())
subObjects->write_image(os, cel->image());
write_image(os, cel->image());
}
write16(os, celdatas);
for (it=begin; it != end; ++it) {
Cel* cel = *it;
if (!cel->link())
write_celdata(os, cel->dataRef());
}
// Cels
write16(os, static_cast<LayerImage*>(layer)->getCelsCount());
for (it=begin; it != end; ++it) {
Cel* cel = *it;
subObjects->write_cel(os, cel);
write_cel(os, cel);
}
break;
}
@ -75,15 +93,16 @@ void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer)
write16(os, static_cast<LayerFolder*>(layer)->getLayersCount());
for (; it != end; ++it)
subObjects->write_layer(os, *it);
write_layer(os, *it);
break;
}
}
}
Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
Layer* read_layer(std::istream& is, SubObjectsIO* subObjects)
{
ObjectId id = read32(is);
uint16_t name_length = read16(is); // Name length
std::vector<char> name(name_length+1);
if (name_length > 0) {
@ -102,20 +121,27 @@ Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
case ObjectType::LayerImage: {
// Create layer
layer.reset(new LayerImage(sprite));
layer.reset(new LayerImage(subObjects->sprite()));
// Read images
int images = read16(is); // Number of images
for (int c=0; c<images; ++c) {
ImageRef image(subObjects->read_image(is));
subObjects->add_image_ref(image);
ImageRef image(read_image(is));
subObjects->addImageRef(image);
}
// Read celdatas
int celdatas = read16(is);
for (int c=0; c<celdatas; ++c) {
CelDataRef celdata(read_celdata(is, subObjects));
subObjects->addCelDataRef(celdata);
}
// Read cels
int cels = read16(is); // Number of cels
for (int c=0; c<cels; ++c) {
// Read the cel
Cel* cel = subObjects->read_cel(is);
Cel* cel = read_cel(is, subObjects);
// Add the cel in the layer
static_cast<LayerImage*>(layer.get())->addCel(cel);
@ -125,12 +151,12 @@ Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
case ObjectType::LayerFolder: {
// Create the layer set
layer.reset(new LayerFolder(sprite));
layer.reset(new LayerFolder(subObjects->sprite()));
// Number of sub-layers
int layers = read16(is);
for (int c=0; c<layers; c++) {
Layer* child = subObjects->read_layer(is);
Layer* child = read_layer(is, subObjects);
if (child)
static_cast<LayerFolder*>(layer.get())->addLayer(child);
else
@ -144,9 +170,10 @@ Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite)
}
if (layer != NULL) {
if (layer) {
layer->setName(&name[0]);
layer->setFlags(static_cast<LayerFlags>(flags));
layer->setId(id);
}
return layer.release();

View File

@ -13,11 +13,7 @@
#include <iosfwd>
namespace doc {
class Cel;
class Image;
class Layer;
class Sprite;
class SubObjectsIO;
// Thrown when a invalid layer type is read from the istream.
@ -26,8 +22,8 @@ namespace doc {
InvalidLayerType(const char* msg) throw() : base::Exception(msg) { }
};
void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer);
Layer* read_layer(std::istream& is, SubObjectsIO* subObjects, Sprite* sprite);
void write_layer(std::ostream& os, Layer* layer);
Layer* read_layer(std::istream& is, SubObjectsIO* subObjects);
} // namespace doc

View File

@ -18,6 +18,7 @@ namespace doc {
Path,
Mask,
Cel,
CelData,
LayerImage,
LayerFolder,
Sprite,

View File

@ -13,6 +13,7 @@
#include "base/memory.h"
#include "base/remove_from_container.h"
#include "base/unique_ptr.h"
#include "doc/cels_range.h"
#include "doc/doc.h"
#include "doc/image_bits.h"
#include "doc/primitives.h"
@ -407,55 +408,42 @@ void Sprite::setDurationForAllFrames(int msecs)
}
//////////////////////////////////////////////////////////////////////
// Images
// Shared Images and CelData (for linked Cels)
ImageRef Sprite::getImage(ObjectId imageId)
ImageRef Sprite::getImageRef(ObjectId imageId)
{
CelList cels;
getCels(cels);
for (auto& cel : cels) {
for (Cel* cel : cels()) {
if (cel->image()->id() == imageId)
return cel->imageRef();
}
return ImageRef(NULL);
return ImageRef(nullptr);
}
CelDataRef Sprite::getCelDataRef(ObjectId celDataId)
{
for (Cel* cel : cels()) {
if (cel->dataRef()->id() == celDataId)
return cel->dataRef();
}
return CelDataRef(nullptr);
}
//////////////////////////////////////////////////////////////////////
// Images
void Sprite::replaceImage(ObjectId curImageId, const ImageRef& newImage)
{
CelList cels;
getCels(cels);
for (auto& cel : cels) {
for (Cel* cel : cels()) {
if (cel->image()->id() == curImageId)
cel->setImage(newImage);
cel->data()->setImage(newImage);
}
}
void Sprite::getCels(CelList& cels) const
{
folder()->getCels(cels);
}
CelList Sprite::cels(frame_t frame) const
{
// TODO create a proper CelsIterator
CelList cels, final;
folder()->getCels(cels);
for (Cel* cel : cels) {
if (cel->frame() == frame)
final.push_back(cel);
}
return final;
}
// TODO replace it with a images iterator
void Sprite::getImages(std::vector<Image*>& images) const
{
CelList cels;
getCels(cels); // TODO create a cel iterator
for (const auto& cel : cels)
if (!cel->link())
images.push_back(cel->image());
for (const auto& cel : uniqueCels())
images.push_back(cel->image());
}
void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const std::vector<uint8_t>& mapping)
@ -463,12 +451,7 @@ void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const std::vector<u
ASSERT(m_format == IMAGE_INDEXED);
ASSERT(mapping.size() == 256);
CelList cels;
getCels(cels);
for (CelIterator it = cels.begin(); it != cels.end(); ++it) {
Cel* cel = *it;
for (Cel* cel : cels()) {
// Remap this Cel because is inside the specified range
if (cel->frame() >= frameFrom &&
cel->frame() <= frameTo) {
@ -534,6 +517,24 @@ void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList
fflush(stdout);
}
//////////////////////////////////////////////////////////////////////
// CelsRange
CelsRange Sprite::cels() const
{
return CelsRange(this, frame_t(0), lastFrame());
}
CelsRange Sprite::cels(frame_t frame) const
{
return CelsRange(this, frame, frame);
}
CelsRange Sprite::uniqueCels() const
{
return CelsRange(this, frame_t(0), lastFrame(), CelsRange::UNIQUE);
}
//////////////////////////////////////////////////////////////////////
static Layer* index2layer(const Layer* layer, const LayerIndex& index, int* index_count)

View File

@ -9,6 +9,7 @@
#pragma once
#include "base/disable_copying.h"
#include "doc/cel_data.h"
#include "doc/cel_list.h"
#include "doc/color.h"
#include "doc/frame.h"
@ -23,6 +24,7 @@
namespace doc {
class CelsRange;
class Document;
class Image;
class Layer;
@ -117,18 +119,23 @@ namespace doc {
void setFrameRangeDuration(frame_t from, frame_t to, int msecs);
void setDurationForAllFrames(int msecs);
////////////////////////////////////////
// Shared Images and CelData (for linked Cels)
ImageRef getImageRef(ObjectId imageId);
CelDataRef getCelDataRef(ObjectId celDataId);
////////////////////////////////////////
// Images
ImageRef getImage(ObjectId imageId);
void replaceImage(ObjectId curImageId, const ImageRef& newImage);
void getCels(CelList& cels) 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;
// Returns the list of cels in the given frame
CelList cels(frame_t frame) const;
CelsRange cels() const;
CelsRange cels(frame_t frame) const;
CelsRange uniqueCels() const;
private:
Document* m_document;

108
src/doc/sprite_tests.cpp Normal file
View File

@ -0,0 +1,108 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 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 <gtest/gtest.h>
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/layer.h"
#include "doc/pixel_format.h"
#include "doc/sprite.h"
using namespace doc;
// lay1 = A _ B
// lay2 = C D E
TEST(Sprite, CelsRange)
{
Sprite* spr = new Sprite(IMAGE_RGB, 32, 32, 256);
spr->setTotalFrames(3);
LayerImage* lay1 = new LayerImage(spr);
LayerImage* lay2 = new LayerImage(spr);
spr->folder()->addLayer(lay1);
spr->folder()->addLayer(lay2);
ImageRef imgA(Image::create(IMAGE_RGB, 32, 32));
Cel* celA = new Cel(frame_t(0), imgA);
Cel* celB = Cel::createLink(celA);
celB->setFrame(frame_t(2));
lay1->addCel(celA);
lay1->addCel(celB);
ImageRef imgC(Image::create(IMAGE_RGB, 32, 32));
Cel* celC = new Cel(frame_t(0), imgC);
Cel* celD = Cel::createCopy(celC);
Cel* celE = Cel::createLink(celD);
celD->setFrame(frame_t(1));
celE->setFrame(frame_t(2));
lay2->addCel(celC);
lay2->addCel(celD);
lay2->addCel(celE);
int i = 0;
for (Cel* cel : spr->cels()) {
switch (i) {
case 0: EXPECT_EQ(cel, celA); break;
case 1: EXPECT_EQ(cel, celB); break;
case 2: EXPECT_EQ(cel, celC); break;
case 3: EXPECT_EQ(cel, celD); break;
case 4: EXPECT_EQ(cel, celE); break;
}
++i;
}
EXPECT_EQ(5, i);
i = 0;
for (Cel* cel : spr->uniqueCels()) {
switch (i) {
case 0: EXPECT_EQ(cel, celA); break;
case 1: EXPECT_EQ(cel, celC); break;
case 2: EXPECT_EQ(cel, celD); break;
}
++i;
}
EXPECT_EQ(3, i);
i = 0;
for (Cel* cel : spr->cels(frame_t(0))) {
switch (i) {
case 0: EXPECT_EQ(cel, celA); break;
case 1: EXPECT_EQ(cel, celC); break;
}
++i;
}
EXPECT_EQ(2, i);
i = 0;
for (Cel* cel : spr->cels(frame_t(1))) {
switch (i) {
case 0: EXPECT_EQ(cel, celD); break;
}
++i;
}
EXPECT_EQ(1, i);
i = 0;
for (Cel* cel : spr->cels(frame_t(2))) {
switch (i) {
case 0: EXPECT_EQ(cel, celB); break;
case 1: EXPECT_EQ(cel, celE); break;
}
++i;
}
EXPECT_EQ(2, i);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

70
src/doc/subobjects_io.cpp Normal file
View File

@ -0,0 +1,70 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 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/subobjects_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 "doc/sprite.h"
namespace doc {
using namespace doc;
SubObjectsIO::SubObjectsIO(Sprite* sprite)
: m_sprite(sprite)
{
}
void SubObjectsIO::addImageRef(const ImageRef& image)
{
ASSERT(image);
ASSERT(!getImageRef(image->id()));
m_images.insert(std::make_pair(image->id(), image));
}
ImageRef SubObjectsIO::getImageRef(ObjectId imageId)
{
auto it = m_images.find(imageId);
if (it != m_images.end()) {
ImageRef image = it->second;
ASSERT(image->id() == imageId);
ASSERT(!m_sprite->getImageRef(imageId));
return image;
}
else
return m_sprite->getImageRef(imageId);
}
void SubObjectsIO::addCelDataRef(const CelDataRef& celdata)
{
ASSERT(celdata);
ASSERT(!getCelDataRef(celdata->id()));
m_celdatas.insert(std::make_pair(celdata->id(), celdata));
}
CelDataRef SubObjectsIO::getCelDataRef(ObjectId celdataId)
{
auto it = m_celdatas.find(celdataId);
if (it != m_celdatas.end()) {
CelDataRef celdata = it->second;
ASSERT(celdata->id() == celdataId);
ASSERT(!m_sprite->getCelDataRef(celdataId));
return celdata;
}
else
return m_sprite->getCelDataRef(celdataId);
}
} // namespace doc

View File

@ -8,33 +8,38 @@
#define DOC_SUBOBJECTS_IO_H_INCLUDED
#pragma once
#include "doc/cel_data.h"
#include "doc/image_ref.h"
#include <iosfwd>
#include <map>
namespace doc {
class Sprite;
class Cel;
class Image;
class Layer;
// Interface used to read sub-objects of a layer or cel.
// Helper class used to read children-objects by layers and cels.
class SubObjectsIO {
public:
virtual ~SubObjectsIO() { }
SubObjectsIO(Sprite* sprite);
// 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;
Sprite* sprite() const { return m_sprite; }
// 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 addImageRef(const ImageRef& image);
void addCelDataRef(const CelDataRef& celdata);
virtual void add_image_ref(const ImageRef& image) = 0;
virtual ImageRef get_image_ref(ObjectId imageId) = 0;
ImageRef getImageRef(ObjectId imageId);
CelDataRef getCelDataRef(ObjectId celdataId);
private:
Sprite* m_sprite;
// Images list that can be queried from doc::read_celdata() using
// getImageRef().
std::map<ObjectId, ImageRef> m_images;
// CelData list that can be queried from doc::read_cel() using
// getCelDataRef().
std::map<ObjectId, CelDataRef> m_celdatas;
};
} // namespace doc