mirror of https://github.com/aseprite/aseprite.git
				
				
				
			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:
		
							parent
							
								
									e975d1c710
								
							
						
					
					
						commit
						3ebb708000
					
				
							
								
								
									
										1
									
								
								TODO.md
								
								
								
								
							
							
						
						
									
										1
									
								
								TODO.md
								
								
								
								
							|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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)); | ||||
|     } | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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)); | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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 | ||||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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
 | ||||
|  | @ -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)); | ||||
|     } | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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()) | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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)                     \ | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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 | ||||
|  | @ -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(); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -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 | ||||
|  | @ -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(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -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 | ||||
|  | @ -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(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ namespace doc { | |||
|     Path, | ||||
|     Mask, | ||||
|     Cel, | ||||
|     CelData, | ||||
|     LayerImage, | ||||
|     LayerFolder, | ||||
|     Sprite, | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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
 | ||||
|  | @ -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
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue