mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-02 04:59:24 +00:00
Merge branch 'feature/continuous-cels'
This commit is contained in:
commit
52003da721
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
|
||||
|
@ -648,6 +648,7 @@
|
||||
<item command="CelProperties" text="&Properties..." />
|
||||
<separator />
|
||||
<item command="ClearCel" text="&Clear" />
|
||||
<item command="UnlinkCel" text="&Unlink" />
|
||||
</menu>
|
||||
|
||||
<menu id="cel_movement_popup">
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -296,6 +296,10 @@
|
||||
<part id="timeline_open_padlock_active" x="252" y="36" w="12" h="12" />
|
||||
<part id="timeline_closed_padlock_normal" x="240" y="48" w="12" h="12" />
|
||||
<part id="timeline_closed_padlock_active" x="252" y="48" w="12" h="12" />
|
||||
<part id="timeline_continuous_normal" x="276" y="36" w="12" h="12" />
|
||||
<part id="timeline_continuous_active" x="288" y="36" w="12" h="12" />
|
||||
<part id="timeline_discontinuous_normal" x="276" y="48" w="12" h="12" />
|
||||
<part id="timeline_discontinuous_active" x="288" y="48" w="12" h="12" />
|
||||
<part id="timeline_empty_frame_normal" x="240" y="60" w="12" h="12" />
|
||||
<part id="timeline_empty_frame_active" x="252" y="60" w="12" h="12" />
|
||||
<part id="timeline_keyframe_normal" x="240" y="72" w="12" h="12" />
|
||||
@ -306,6 +310,9 @@
|
||||
<part id="timeline_fromright_active" x="252" y="96" w="12" h="12" />
|
||||
<part id="timeline_fromboth_normal" x="240" y="108" w="12" h="12" />
|
||||
<part id="timeline_fromboth_active" x="252" y="108" w="12" h="12" />
|
||||
<part id="timeline_leftlink_active" x="264" y="84" w="12" h="12" />
|
||||
<part id="timeline_bothlinks_active" x="264" y="96" w="12" h="12" />
|
||||
<part id="timeline_rightlink_active" x="264" y="108" w="12" h="12" />
|
||||
<part id="timeline_gear" x="264" y="12" w="12" h="12" />
|
||||
<part id="timeline_gear_active" x="264" y="24" w="12" h="12" />
|
||||
<part id="timeline_onionskin" x="264" y="36" w="12" h="12" />
|
||||
@ -434,6 +441,20 @@
|
||||
<icon part="timeline_closed_padlock_active" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_continuous -->
|
||||
<style id="timeline_continuous" base="timeline_box">
|
||||
<icon part="timeline_continuous_normal" />
|
||||
</style>
|
||||
<style id="timeline_continuous:active">
|
||||
<icon part="timeline_continuous_active" />
|
||||
</style>
|
||||
<style id="timeline_discontinuous" base="timeline_box">
|
||||
<icon part="timeline_discontinuous_normal" />
|
||||
</style>
|
||||
<style id="timeline_discontinuous:active">
|
||||
<icon part="timeline_discontinuous_active" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_layer -->
|
||||
<style id="timeline_layer" base="timeline_box">
|
||||
<text align="left" valign="middle" padding-left="4" />
|
||||
@ -482,6 +503,16 @@
|
||||
<icon part="timeline_fromboth_active" />
|
||||
</style>
|
||||
|
||||
<style id="timeline_leftlink">
|
||||
<icon part="timeline_leftlink_active" />
|
||||
</style>
|
||||
<style id="timeline_rightlink">
|
||||
<icon part="timeline_rightlink_active" />
|
||||
</style>
|
||||
<style id="timeline_bothlinks">
|
||||
<icon part="timeline_bothlinks_active" />
|
||||
</style>
|
||||
|
||||
<!-- timeline_gear -->
|
||||
<style id="timeline_gear" base="timeline_box">
|
||||
<icon part="timeline_gear" />
|
||||
|
@ -119,6 +119,7 @@ Layer Chunk (0x2004)
|
||||
2 = Editable
|
||||
4 = Lock movement
|
||||
8 = Background
|
||||
16 = Prefer linked cels
|
||||
WORD Layer type (0=normal (image) layer, 1=layer set)
|
||||
WORD Layer child level (see NOTE.1)
|
||||
WORD Default layer width in pixels (ignored)
|
||||
|
@ -75,13 +75,13 @@ 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_opacity.cpp
|
||||
cmd/set_cel_position.cpp
|
||||
@ -95,6 +95,7 @@ add_library(app-lib
|
||||
cmd/set_sprite_size.cpp
|
||||
cmd/set_total_frames.cpp
|
||||
cmd/set_transparent_color.cpp
|
||||
cmd/unlink_cel.cpp
|
||||
cmd/with_cel.cpp
|
||||
cmd/with_document.cpp
|
||||
cmd/with_image.cpp
|
||||
@ -185,6 +186,7 @@ add_library(app-lib
|
||||
commands/cmd_switch_colors.cpp
|
||||
commands/cmd_timeline.cpp
|
||||
commands/cmd_undo.cpp
|
||||
commands/cmd_unlink_cel.cpp
|
||||
commands/cmd_zoom.cpp
|
||||
commands/command.cpp
|
||||
commands/commands.cpp
|
||||
|
@ -22,15 +22,21 @@
|
||||
|
||||
#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 {
|
||||
|
||||
using namespace base::serialization;
|
||||
using namespace base::serialization::little_endian;
|
||||
using namespace doc;
|
||||
|
||||
AddCel::AddCel(Layer* layer, Cel* cel)
|
||||
@ -52,7 +58,14 @@ void AddCel::onUndo()
|
||||
Layer* layer = this->layer();
|
||||
Cel* cel = this->cel();
|
||||
|
||||
ObjectIO(layer->sprite()).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);
|
||||
}
|
||||
@ -60,7 +73,17 @@ void AddCel::onUndo()
|
||||
void AddCel::onRedo()
|
||||
{
|
||||
Layer* layer = this->layer();
|
||||
Cel* cel = ObjectIO(layer->sprite()).read_cel(m_stream);
|
||||
|
||||
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 = 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,6 +27,8 @@
|
||||
#include "app/cmd/clear_cel.h"
|
||||
#include "app/cmd/copy_rect.h"
|
||||
#include "app/cmd/remove_cel.h"
|
||||
#include "app/cmd/set_cel_data.h"
|
||||
#include "app/cmd/unlink_cel.h"
|
||||
#include "app/document.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
@ -70,8 +72,11 @@ void CopyCel::onExecute()
|
||||
|
||||
// Clear destination cel if it does exist. It'll be overriden by the
|
||||
// copy of srcCel.
|
||||
if (dstCel)
|
||||
if (dstCel) {
|
||||
if (dstCel->links())
|
||||
executeAndAdd(new cmd::UnlinkCel(dstCel));
|
||||
executeAndAdd(new cmd::ClearCel(dstCel));
|
||||
}
|
||||
|
||||
// Add empty frames until newFrame
|
||||
while (dstSprite->totalFrames() <= m_dstFrame)
|
||||
@ -83,35 +88,41 @@ void CopyCel::onExecute()
|
||||
if (dstCel)
|
||||
dstImage = dstCel->imageRef();
|
||||
|
||||
if (dstLayer->isBackground()) {
|
||||
if (srcCel) {
|
||||
ASSERT(dstImage);
|
||||
if (dstImage) {
|
||||
int blend = (srcLayer->isBackground() ?
|
||||
BLEND_MODE_COPY: BLEND_MODE_NORMAL);
|
||||
bool createLink =
|
||||
(srcLayer == dstLayer && dstLayer->isContinuous());
|
||||
|
||||
ImageRef tmp(Image::createCopy(dstImage));
|
||||
render::composite_image(tmp, srcImage,
|
||||
srcCel->x(), srcCel->y(), 255, blend);
|
||||
executeAndAdd(new cmd::CopyRect(dstImage, tmp, gfx::Clip(tmp->bounds())));
|
||||
}
|
||||
// For background layer
|
||||
if (dstLayer->isBackground()) {
|
||||
ASSERT(dstCel);
|
||||
ASSERT(dstImage);
|
||||
if (!dstCel || !dstImage ||
|
||||
!srcCel || !srcImage)
|
||||
return;
|
||||
|
||||
if (createLink) {
|
||||
executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
|
||||
}
|
||||
else {
|
||||
ASSERT(dstCel);
|
||||
if (dstCel)
|
||||
executeAndAdd(new cmd::ClearCel(dstCel));
|
||||
int blend = (srcLayer->isBackground() ?
|
||||
BLEND_MODE_COPY: BLEND_MODE_NORMAL);
|
||||
|
||||
ImageRef tmp(Image::createCopy(dstImage));
|
||||
render::composite_image(tmp, srcImage,
|
||||
srcCel->x(), srcCel->y(), 255, blend);
|
||||
executeAndAdd(new cmd::CopyRect(dstImage, tmp, gfx::Clip(tmp->bounds())));
|
||||
}
|
||||
}
|
||||
// For transparent layers
|
||||
else {
|
||||
if (dstCel)
|
||||
executeAndAdd(new cmd::RemoveCel(dstCel));
|
||||
|
||||
if (srcCel) {
|
||||
dstImage.reset(Image::createCopy(srcImage));
|
||||
|
||||
dstCel = new Cel(*srcCel);
|
||||
if (createLink)
|
||||
dstCel = Cel::createLink(srcCel);
|
||||
else
|
||||
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,7 +28,9 @@
|
||||
#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/unlink_cel.h"
|
||||
#include "app/document.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
@ -72,8 +74,11 @@ void MoveCel::onExecute()
|
||||
|
||||
// Clear destination cel if it does exist. It'll be overriden by the
|
||||
// copy of srcCel.
|
||||
if (dstCel)
|
||||
if (dstCel) {
|
||||
if (dstCel->links())
|
||||
executeAndAdd(new cmd::UnlinkCel(dstCel));
|
||||
executeAndAdd(new cmd::ClearCel(dstCel));
|
||||
}
|
||||
|
||||
// Add empty frames until newFrame
|
||||
while (dstSprite->totalFrames() <= m_dstFrame)
|
||||
@ -85,49 +90,47 @@ void MoveCel::onExecute()
|
||||
if (dstCel)
|
||||
dstImage = dstCel->imageRef();
|
||||
|
||||
if (srcCel) {
|
||||
if (srcLayer == dstLayer) {
|
||||
if (dstLayer->isBackground()) {
|
||||
ASSERT(dstImage);
|
||||
if (dstImage) {
|
||||
int blend = (srcLayer->isBackground() ?
|
||||
BLEND_MODE_COPY: BLEND_MODE_NORMAL);
|
||||
bool createLink =
|
||||
(srcLayer == dstLayer && dstLayer->isContinuous());
|
||||
|
||||
ImageRef tmp(Image::createCopy(dstImage));
|
||||
render::composite_image(tmp, srcImage,
|
||||
srcCel->x(), srcCel->y(), 255, blend);
|
||||
executeAndAdd(new cmd::CopyRect(dstImage, tmp, gfx::Clip(tmp->bounds())));
|
||||
}
|
||||
// For background layer
|
||||
if (dstLayer->isBackground()) {
|
||||
ASSERT(dstCel);
|
||||
ASSERT(dstImage);
|
||||
if (!dstCel || !dstImage ||
|
||||
!srcCel || !srcImage)
|
||||
return;
|
||||
|
||||
executeAndAdd(new cmd::ClearImage(srcImage,
|
||||
static_cast<app::Document*>(srcSprite->document())
|
||||
->bgColor(srcLayer)));
|
||||
}
|
||||
// Move the cel in the same layer.
|
||||
else {
|
||||
executeAndAdd(new cmd::SetCelFrame(srcCel, m_dstFrame));
|
||||
}
|
||||
if (createLink) {
|
||||
executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
|
||||
executeAndAdd(new cmd::UnlinkCel(srcCel));
|
||||
}
|
||||
// Move the cel between different layers.
|
||||
else {
|
||||
if (!dstCel) {
|
||||
dstImage.reset(Image::createCopy(srcImage));
|
||||
int blend = (srcLayer->isBackground() ?
|
||||
BLEND_MODE_COPY: BLEND_MODE_NORMAL);
|
||||
|
||||
dstCel = new Cel(*srcCel);
|
||||
dstCel->setFrame(m_dstFrame);
|
||||
dstCel->setImage(dstImage);
|
||||
}
|
||||
ImageRef tmp(Image::createCopy(dstImage));
|
||||
render::composite_image(tmp, srcImage,
|
||||
srcCel->x(), srcCel->y(), 255, blend);
|
||||
executeAndAdd(new cmd::CopyRect(dstImage, tmp, gfx::Clip(tmp->bounds())));
|
||||
}
|
||||
executeAndAdd(new cmd::ClearCel(srcCel));
|
||||
}
|
||||
// For transparent layers
|
||||
else if (srcCel) {
|
||||
ASSERT(!dstCel);
|
||||
if (dstCel)
|
||||
return;
|
||||
|
||||
if (dstLayer->isBackground()) {
|
||||
ImageRef tmp(Image::createCopy(dstImage));
|
||||
render::composite_image(tmp, srcImage,
|
||||
srcCel->x(), srcCel->y(), 255, BLEND_MODE_NORMAL);
|
||||
executeAndAdd(new cmd::CopyRect(dstImage, tmp, gfx::Clip(tmp->bounds())));
|
||||
}
|
||||
else {
|
||||
executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
|
||||
}
|
||||
// Move the cel in the same layer.
|
||||
if (srcLayer == dstLayer) {
|
||||
executeAndAdd(new cmd::SetCelFrame(srcCel, m_dstFrame));
|
||||
}
|
||||
else {
|
||||
dstCel = Cel::createCopy(srcCel);
|
||||
dstCel->setFrame(m_dstFrame);
|
||||
|
||||
executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
|
||||
executeAndAdd(new cmd::ClearCel(srcCel));
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +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"
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
@ -1,92 +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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // 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);
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
#include "app/cmd.h"
|
||||
#include "app/cmd/with_sprite.h"
|
||||
// #include "app/cmd/with_image.h"
|
||||
#include "doc/image_ref.h"
|
||||
|
||||
#include <sstream>
|
||||
|
96
src/app/cmd/set_cel_data.cpp
Normal file
96
src/app/cmd/set_cel_data.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/* 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/set_cel_data.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;
|
||||
|
||||
SetCelData::SetCelData(Cel* cel, const CelDataRef& newData)
|
||||
: WithCel(cel)
|
||||
, m_oldDataId(cel->data()->id())
|
||||
, m_oldImageId(cel->image()->id())
|
||||
, m_newDataId(newData->id())
|
||||
, m_newData(newData)
|
||||
{
|
||||
}
|
||||
|
||||
void SetCelData::onExecute()
|
||||
{
|
||||
Cel* cel = this->cel();
|
||||
if (!cel->links())
|
||||
createCopy();
|
||||
|
||||
cel->setDataRef(m_newData);
|
||||
m_newData.reset(nullptr);
|
||||
}
|
||||
|
||||
void SetCelData::onUndo()
|
||||
{
|
||||
Cel* cel = this->cel();
|
||||
|
||||
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 {
|
||||
CelDataRef oldData = cel->sprite()->getCelDataRef(m_oldDataId);
|
||||
ASSERT(oldData);
|
||||
cel->setDataRef(oldData);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
ASSERT(!m_dataCopy);
|
||||
m_dataCopy.reset(new CelData(*cel->data()));
|
||||
m_dataCopy->setImage(ImageRef(Image::createCopy(cel->image())));
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
64
src/app/cmd/set_cel_data.h
Normal file
64
src/app/cmd/set_cel_data.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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 3 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_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/cel_data.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
using namespace doc;
|
||||
|
||||
class SetCelData : public Cmd
|
||||
, public WithCel {
|
||||
public:
|
||||
SetCelData(Cel* cel, const CelDataRef& newData);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
void onUndo() override;
|
||||
void onRedo() override;
|
||||
size_t onMemSize() const override {
|
||||
return sizeof(*this) +
|
||||
(m_dataCopy ? m_dataCopy->getMemSize(): 0);
|
||||
}
|
||||
|
||||
private:
|
||||
void createCopy();
|
||||
|
||||
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.
|
||||
CelDataRef m_newData;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -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));
|
||||
}
|
||||
|
75
src/app/cmd/unlink_cel.cpp
Normal file
75
src/app/cmd/unlink_cel.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/* 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/unlink_cel.h"
|
||||
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
UnlinkCel::UnlinkCel(Cel* cel)
|
||||
: WithCel(cel)
|
||||
, m_newImageId(0)
|
||||
, m_oldCelDataId(cel->dataRef()->id())
|
||||
, m_newCelDataId(0)
|
||||
{
|
||||
ASSERT(cel->links());
|
||||
}
|
||||
|
||||
void UnlinkCel::onExecute()
|
||||
{
|
||||
Cel* cel = this->cel();
|
||||
CelDataRef oldCelData = cel->sprite()->getCelDataRef(m_oldCelDataId);
|
||||
ASSERT(oldCelData);
|
||||
|
||||
ImageRef imgCopy(Image::createCopy(oldCelData->image()));
|
||||
CelDataRef celDataCopy(new CelData(*oldCelData));
|
||||
celDataCopy->setImage(imgCopy);
|
||||
|
||||
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();
|
||||
CelDataRef oldCelData = cel->sprite()->getCelDataRef(m_oldCelDataId);
|
||||
ASSERT(oldCelData);
|
||||
|
||||
cel->setDataRef(oldCelData);
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
48
src/app/cmd/unlink_cel.h
Normal file
48
src/app/cmd/unlink_cel.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* 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_UNLINK_CEL_H_INCLUDED
|
||||
#define APP_CMD_UNLINK_CEL_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/cmd.h"
|
||||
#include "app/cmd/with_cel.h"
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
using namespace doc;
|
||||
|
||||
class UnlinkCel : public Cmd
|
||||
, public WithCel {
|
||||
public:
|
||||
UnlinkCel(Cel* cel);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
void onUndo() override;
|
||||
|
||||
private:
|
||||
ObjectId m_newImageId;
|
||||
ObjectId m_oldCelDataId;
|
||||
ObjectId m_newCelDataId;
|
||||
};
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -25,9 +25,10 @@
|
||||
#include "app/context_access.h"
|
||||
#include "app/document_api.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
@ -53,17 +54,14 @@ ClearCelCommand::ClearCelCommand()
|
||||
|
||||
bool ClearCelCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||
ContextFlags::ActiveLayerIsVisible |
|
||||
ContextFlags::ActiveLayerIsEditable |
|
||||
ContextFlags::ActiveLayerIsImage |
|
||||
ContextFlags::HasActiveCel);
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
||||
}
|
||||
|
||||
void ClearCelCommand::onExecute(Context* context)
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Document* document(writer.document());
|
||||
bool nonEditableLayers = false;
|
||||
{
|
||||
Transaction transaction(writer.context(), "Clear Cel");
|
||||
|
||||
@ -83,16 +81,29 @@ void ClearCelCommand::onExecute(Context* context)
|
||||
begin = range.frameBegin()-1;
|
||||
frame != begin;
|
||||
--frame) {
|
||||
document->getApi(transaction).clearCel(layerImage, frame);
|
||||
if (layerImage->cel(frame)) {
|
||||
if (layerImage->isEditable())
|
||||
document->getApi(transaction).clearCel(layerImage, frame);
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
document->getApi(transaction).clearCel(writer.cel());
|
||||
else if (writer.cel()) {
|
||||
if (writer.layer()->isEditable())
|
||||
document->getApi(transaction).clearCel(writer.cel());
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
if (nonEditableLayers)
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"There are locked layers");
|
||||
|
||||
update_screen_for_document(document);
|
||||
}
|
||||
|
||||
|
@ -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,7 +93,7 @@ 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());
|
||||
|
||||
@ -152,23 +153,17 @@ 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
|
||||
(sprite, cel,
|
||||
(m_flipType == doc::algorithm::FlipHorizontal ?
|
||||
sprite->width() - image->width() - cel->x():
|
||||
cel->x()),
|
||||
(m_flipType == doc::algorithm::FlipVertical ?
|
||||
sprite->height() - image->height() - cel->y():
|
||||
cel->y()));
|
||||
(m_flipType == doc::algorithm::FlipHorizontal ?
|
||||
sprite->width() - image->width() - cel->x():
|
||||
cel->x()),
|
||||
(m_flipType == doc::algorithm::FlipVertical ?
|
||||
sprite->height() - image->height() - cel->y():
|
||||
cel->y()));
|
||||
|
||||
api.flipImage(image, image->bounds(), m_flipType);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "app/cmd/add_cel.h"
|
||||
#include "app/cmd/replace_image.h"
|
||||
#include "app/cmd/set_cel_position.h"
|
||||
#include "app/cmd/unlink_cel.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/document.h"
|
||||
@ -147,6 +148,9 @@ void MergeDownLayerCommand::onExecute(Context* context)
|
||||
transaction.execute(new cmd::SetCelPosition(dst_cel,
|
||||
bounds.x, bounds.y));
|
||||
|
||||
if (dst_cel->links())
|
||||
transaction.execute(new cmd::UnlinkCel(dst_cel));
|
||||
|
||||
transaction.execute(new cmd::ReplaceImage(sprite,
|
||||
dst_cel->imageRef(), new_image));
|
||||
}
|
||||
|
@ -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,39 +83,42 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* [working thread]
|
||||
*/
|
||||
// [working thread]
|
||||
virtual void onJob()
|
||||
{
|
||||
Transaction transaction(m_writer.context(), "Rotate Canvas");
|
||||
DocumentApi api = m_document->getApi(transaction);
|
||||
|
||||
// for each cel...
|
||||
// 1) Rotate cel positions
|
||||
for (Cel* cel : m_cels) {
|
||||
Image* image = cel->image();
|
||||
if (!image)
|
||||
continue;
|
||||
|
||||
switch (m_angle) {
|
||||
case 180:
|
||||
api.setCelPosition(m_sprite, cel,
|
||||
m_sprite->width() - cel->x() - image->width(),
|
||||
m_sprite->height() - cel->y() - image->height());
|
||||
break;
|
||||
case 90:
|
||||
api.setCelPosition(m_sprite, cel,
|
||||
m_sprite->height() - cel->y() - image->height(),
|
||||
cel->x());
|
||||
break;
|
||||
case -90:
|
||||
api.setCelPosition(m_sprite, cel,
|
||||
cel->y(),
|
||||
m_sprite->width() - cel->x() - image->width());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Rotate images
|
||||
int i = 0;
|
||||
for (Cel* cel : m_cels) {
|
||||
Image* image = cel->image();
|
||||
if (image) {
|
||||
// change it location
|
||||
switch (m_angle) {
|
||||
case 180:
|
||||
api.setCelPosition(m_sprite, cel,
|
||||
m_sprite->width() - cel->x() - image->width(),
|
||||
m_sprite->height() - cel->y() - image->height());
|
||||
break;
|
||||
case 90:
|
||||
api.setCelPosition(m_sprite, cel,
|
||||
m_sprite->height() - cel->y() - image->height(),
|
||||
cel->x());
|
||||
break;
|
||||
case -90:
|
||||
api.setCelPosition(m_sprite, cel,
|
||||
cel->y(),
|
||||
m_sprite->width() - cel->x() - image->width());
|
||||
break;
|
||||
}
|
||||
|
||||
// rotate the image
|
||||
ImageRef new_image(Image::create(image->pixelFormat(),
|
||||
m_angle == 180 ? image->width(): image->height(),
|
||||
m_angle == 180 ? image->height(): image->width()));
|
||||
@ -214,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,37 +85,35 @@ 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()));
|
||||
|
||||
// Get cel's image
|
||||
Image* image = cel->image();
|
||||
if (!image)
|
||||
continue;
|
||||
if (image && !cel->link()) {
|
||||
// Resize the image
|
||||
int w = scale_x(image->width());
|
||||
int h = scale_y(image->height());
|
||||
ImageRef new_image(Image::create(image->pixelFormat(), MAX(1, w), MAX(1, h)));
|
||||
|
||||
// Resize the image
|
||||
int w = scale_x(image->width());
|
||||
int h = scale_y(image->height());
|
||||
ImageRef new_image(Image::create(image->pixelFormat(), MAX(1, w), MAX(1, h)));
|
||||
|
||||
doc::algorithm::fixup_image_transparent_colors(image);
|
||||
doc::algorithm::resize_image(image, new_image,
|
||||
doc::algorithm::fixup_image_transparent_colors(image);
|
||||
doc::algorithm::resize_image(image, new_image,
|
||||
m_resize_method,
|
||||
m_sprite->palette(cel->frame()),
|
||||
m_sprite->rgbMap(cel->frame()));
|
||||
|
||||
api.replaceImage(m_sprite, cel->imageRef(), new_image);
|
||||
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())
|
||||
|
119
src/app/commands/cmd_unlink_cel.cpp
Normal file
119
src/app/commands/cmd_unlink_cel.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* 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/app.h"
|
||||
#include "app/cmd/unlink_cel.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/timeline.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class UnlinkCelCommand : public Command {
|
||||
public:
|
||||
UnlinkCelCommand();
|
||||
Command* clone() const override { return new UnlinkCelCommand(*this); }
|
||||
|
||||
protected:
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
};
|
||||
|
||||
UnlinkCelCommand::UnlinkCelCommand()
|
||||
: Command("UnlinkCel",
|
||||
"Unlink Cel",
|
||||
CmdRecordableFlag)
|
||||
{
|
||||
}
|
||||
|
||||
bool UnlinkCelCommand::onEnabled(Context* context)
|
||||
{
|
||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable);
|
||||
}
|
||||
|
||||
void UnlinkCelCommand::onExecute(Context* context)
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Document* document(writer.document());
|
||||
bool nonEditableLayers = false;
|
||||
{
|
||||
Transaction transaction(writer.context(), "Unlink Cel");
|
||||
|
||||
// TODO the range of selected frames should be in the DocumentLocation.
|
||||
Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
|
||||
if (range.enabled()) {
|
||||
Sprite* sprite = writer.sprite();
|
||||
|
||||
for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
|
||||
Layer* layer = sprite->indexToLayer(layerIdx);
|
||||
if (!layer->isImage())
|
||||
continue;
|
||||
|
||||
LayerImage* layerImage = static_cast<LayerImage*>(layer);
|
||||
|
||||
for (frame_t frame = range.frameEnd(),
|
||||
begin = range.frameBegin()-1;
|
||||
frame != begin;
|
||||
--frame) {
|
||||
Cel* cel = layerImage->cel(frame);
|
||||
if (cel && cel->links()) {
|
||||
if (layerImage->isEditable())
|
||||
transaction.execute(new cmd::UnlinkCel(cel));
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cel* cel = writer.cel();
|
||||
if (cel && cel->links()) {
|
||||
if (cel->layer()->isEditable())
|
||||
transaction.execute(new cmd::UnlinkCel(writer.cel()));
|
||||
else
|
||||
nonEditableLayers = true;
|
||||
}
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
if (nonEditableLayers)
|
||||
StatusBar::instance()->showTip(1000,
|
||||
"There are locked layers");
|
||||
|
||||
update_screen_for_document(document);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createUnlinkCelCommand()
|
||||
{
|
||||
return new UnlinkCelCommand;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -115,4 +115,5 @@ FOR_EACH_COMMAND(SpriteSize)
|
||||
FOR_EACH_COMMAND(SwitchColors)
|
||||
FOR_EACH_COMMAND(Timeline)
|
||||
FOR_EACH_COMMAND(Undo)
|
||||
FOR_EACH_COMMAND(UnlinkCel)
|
||||
FOR_EACH_COMMAND(Zoom)
|
||||
|
@ -23,24 +23,26 @@
|
||||
#include "app/commands/filters/filter_manager_impl.h"
|
||||
|
||||
#include "app/cmd/copy_rect.h"
|
||||
#include "app/cmd/unlink_cel.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/transaction.h"
|
||||
#include "filters/filter.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/images_collector.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "filters/filter.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -224,11 +226,20 @@ void FilterManagerImpl::applyToTarget()
|
||||
m_progressBase = 0.0f;
|
||||
m_progressWidth = 1.0f / images.size();
|
||||
|
||||
std::set<ObjectId> visited;
|
||||
|
||||
// For each target image
|
||||
for (ImagesCollector::ItemsIterator it = images.begin();
|
||||
for (auto it = images.begin();
|
||||
it != images.end() && !cancelled;
|
||||
++it) {
|
||||
applyToImage(transaction, it->layer(), it->image(), it->cel()->x(), it->cel()->y());
|
||||
Image* image = it->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());
|
||||
}
|
||||
|
||||
// Is there a delegate to know if the process was cancelled by the user?
|
||||
if (m_progressDelegate)
|
||||
|
@ -44,6 +44,8 @@
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace base;
|
||||
@ -355,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);
|
||||
@ -364,18 +367,24 @@ void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, La
|
||||
CelConstIterator it = sourceLayer->getCelBegin();
|
||||
CelConstIterator end = sourceLayer->getCelEnd();
|
||||
|
||||
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);
|
||||
|
||||
ImageRef newImage(Image::createCopy(sourceImage));
|
||||
newCel->setImage(newImage);
|
||||
auto it = linked.find(sourceCel->data()->id());
|
||||
if (it != linked.end()) {
|
||||
newCel.reset(Cel::createLink(it->second));
|
||||
newCel->setFrame(sourceCel->frame());
|
||||
}
|
||||
else {
|
||||
newCel.reset(Cel::createCopy(sourceCel));
|
||||
linked.insert(std::make_pair(sourceCel->data()->id(), newCel.get()));
|
||||
}
|
||||
|
||||
destLayer->addCel(newCel);
|
||||
newCel.release();
|
||||
|
@ -65,6 +65,8 @@
|
||||
#include "render/quantization.h"
|
||||
#include "render/render.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace app {
|
||||
|
||||
DocumentApi::DocumentApi(Document* document, Transaction& transaction)
|
||||
@ -86,11 +88,47 @@ void DocumentApi::setSpriteTransparentColor(Sprite* sprite, color_t maskColor)
|
||||
void DocumentApi::cropSprite(Sprite* sprite, const gfx::Rect& bounds)
|
||||
{
|
||||
setSpriteSize(sprite, bounds.w, bounds.h);
|
||||
displaceLayers(sprite->folder(), -bounds.x, -bounds.y);
|
||||
|
||||
Layer *background_layer = sprite->backgroundLayer();
|
||||
if (background_layer)
|
||||
cropLayer(background_layer, 0, 0, sprite->width(), sprite->height());
|
||||
app::Document* doc = static_cast<app::Document*>(sprite->document());
|
||||
std::vector<Layer*> layers;
|
||||
sprite->getLayersList(layers);
|
||||
for (Layer* layer : layers) {
|
||||
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();
|
||||
if (image && !cel->link()) {
|
||||
ASSERT(cel->x() == 0);
|
||||
ASSERT(cel->y() == 0);
|
||||
|
||||
// Create the new image through a crop
|
||||
ImageRef new_image(
|
||||
crop_image(image,
|
||||
bounds.x, bounds.y,
|
||||
bounds.w, bounds.h,
|
||||
doc->bgColor(layer)));
|
||||
|
||||
// Replace the image in the stock that is pointed by the cel
|
||||
replaceImage(sprite, cel->imageRef(), new_image);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Update the cel's position
|
||||
setCelPosition(sprite, cel,
|
||||
cel->x()-bounds.x, cel->y()-bounds.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_document->mask()->isEmpty())
|
||||
setMaskPosition(m_document->mask()->bounds().x-bounds.x,
|
||||
@ -228,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;
|
||||
@ -298,23 +336,6 @@ void DocumentApi::setCelOpacity(Sprite* sprite, Cel* cel, int newOpacity)
|
||||
m_transaction.execute(new cmd::SetCelOpacity(cel, newOpacity));
|
||||
}
|
||||
|
||||
void DocumentApi::cropCel(Sprite* sprite, Cel* cel, int x, int y, int w, int h)
|
||||
{
|
||||
Image* cel_image = cel->image();
|
||||
ASSERT(cel_image);
|
||||
|
||||
// create the new image through a crop
|
||||
ImageRef new_image(crop_image(cel_image,
|
||||
x-cel->x(), y-cel->y(), w, h,
|
||||
static_cast<app::Document*>(sprite->document())->bgColor(cel->layer())));
|
||||
|
||||
// replace the image in the stock that is pointed by the cel
|
||||
replaceImage(sprite, cel->imageRef(), new_image);
|
||||
|
||||
// update the cel's position
|
||||
setCelPosition(sprite, cel, x, y);
|
||||
}
|
||||
|
||||
void DocumentApi::clearCel(LayerImage* layer, frame_t frame)
|
||||
{
|
||||
if (Cel* cel = layer->cel(frame))
|
||||
@ -406,44 +427,6 @@ void DocumentApi::restackLayerBefore(Layer* layer, Layer* beforeThis)
|
||||
restackLayerAfter(layer, layer->sprite()->indexToLayer(afterThisIdx));
|
||||
}
|
||||
|
||||
void DocumentApi::cropLayer(Layer* layer, int x, int y, int w, int h)
|
||||
{
|
||||
if (!layer->isImage())
|
||||
return;
|
||||
|
||||
Sprite* sprite = layer->sprite();
|
||||
CelIterator it = ((LayerImage*)layer)->getCelBegin();
|
||||
CelIterator end = ((LayerImage*)layer)->getCelEnd();
|
||||
for (; it != end; ++it)
|
||||
cropCel(sprite, *it, x, y, w, h);
|
||||
}
|
||||
|
||||
// Moves every frame in @a layer with the offset (@a dx, @a dy).
|
||||
void DocumentApi::displaceLayers(Layer* layer, int dx, int dy)
|
||||
{
|
||||
switch (layer->type()) {
|
||||
|
||||
case ObjectType::LayerImage: {
|
||||
CelIterator it = ((LayerImage*)layer)->getCelBegin();
|
||||
CelIterator end = ((LayerImage*)layer)->getCelEnd();
|
||||
for (; it != end; ++it) {
|
||||
Cel* cel = *it;
|
||||
setCelPosition(layer->sprite(), cel, cel->x()+dx, cel->y()+dy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjectType::LayerFolder: {
|
||||
LayerIterator it = ((LayerFolder*)layer)->getLayerBegin();
|
||||
LayerIterator end = ((LayerFolder*)layer)->getLayerEnd();
|
||||
for (; it != end; ++it)
|
||||
displaceLayers(*it, dx, dy);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentApi::backgroundFromLayer(Layer* layer)
|
||||
{
|
||||
m_transaction.execute(new cmd::BackgroundFromLayer(layer));
|
||||
@ -499,11 +482,6 @@ void DocumentApi::replaceImage(Sprite* sprite, const ImageRef& oldImage, const I
|
||||
sprite, oldImage, newImage));
|
||||
}
|
||||
|
||||
void DocumentApi::clearImage(Image* image, color_t bgcolor)
|
||||
{
|
||||
m_transaction.execute(new cmd::ClearImage(image, bgcolor));
|
||||
}
|
||||
|
||||
void DocumentApi::flipImage(Image* image, const gfx::Rect& bounds,
|
||||
doc::algorithm::FlipType flipType)
|
||||
{
|
||||
|
@ -78,7 +78,6 @@ namespace app {
|
||||
void clearCel(Cel* cel);
|
||||
void setCelPosition(Sprite* sprite, Cel* cel, int x, int y);
|
||||
void setCelOpacity(Sprite* sprite, Cel* cel, int newOpacity);
|
||||
void cropCel(Sprite* sprite, Cel* cel, int x, int y, int w, int h);
|
||||
void moveCel(
|
||||
LayerImage* srcLayer, frame_t srcFrame,
|
||||
LayerImage* dstLayer, frame_t dstFrame);
|
||||
@ -95,8 +94,6 @@ namespace app {
|
||||
void removeLayer(Layer* layer);
|
||||
void restackLayerAfter(Layer* layer, Layer* afterThis);
|
||||
void restackLayerBefore(Layer* layer, Layer* beforeThis);
|
||||
void cropLayer(Layer* layer, int x, int y, int w, int h);
|
||||
void displaceLayers(Layer* layer, int dx, int dy);
|
||||
void backgroundFromLayer(Layer* layer);
|
||||
void layerFromBackground(Layer* layer);
|
||||
void flattenLayers(Sprite* sprite);
|
||||
@ -107,7 +104,6 @@ namespace app {
|
||||
void replaceImage(Sprite* sprite, const ImageRef& oldImage, const ImageRef& newImage);
|
||||
|
||||
// Image API
|
||||
void clearImage(Image* image, color_t bgcolor);
|
||||
void flipImage(Image* image, const gfx::Rect& bounds, doc::algorithm::FlipType flipType);
|
||||
void flipImageWithMask(Layer* layer, Image* image, doc::algorithm::FlipType flipType);
|
||||
|
||||
|
@ -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 1 // Create a copy of the linked cel (avoid using links cel)
|
||||
ImageRef image(Image::createCopy(link->image()));
|
||||
cel->setImage(image);
|
||||
#else
|
||||
cel->setImage(link->imageRef());
|
||||
#endif
|
||||
// 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)
|
||||
|
@ -461,7 +461,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) \
|
||||
|
@ -80,7 +80,7 @@ bool FliFormat::onLoad(FileOp* fop)
|
||||
int c, w, h;
|
||||
frame_t frpos_in;
|
||||
frame_t frpos_out;
|
||||
int index = 0;
|
||||
int index = 0; // TODO this is used to create linked cels
|
||||
|
||||
// Open the file to read in binary mode
|
||||
FileHandle f(open_file_with_exception(fop->filename, "rb"));
|
||||
|
@ -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 {
|
||||
|
@ -91,12 +91,17 @@ static const char* kTimelineOpenEye = "timeline_open_eye";
|
||||
static const char* kTimelineClosedEye = "timeline_closed_eye";
|
||||
static const char* kTimelineOpenPadlock = "timeline_open_padlock";
|
||||
static const char* kTimelineClosedPadlock = "timeline_closed_padlock";
|
||||
static const char* kTimelineContinuous = "timeline_continuous";
|
||||
static const char* kTimelineDiscontinuous = "timeline_discontinuous";
|
||||
static const char* kTimelineLayer = "timeline_layer";
|
||||
static const char* kTimelineEmptyFrame = "timeline_empty_frame";
|
||||
static const char* kTimelineKeyframe = "timeline_keyframe";
|
||||
static const char* kTimelineFromLeft = "timeline_fromleft";
|
||||
static const char* kTimelineFromRight = "timeline_fromright";
|
||||
static const char* kTimelineFromBoth = "timeline_fromboth";
|
||||
static const char* kTimelineLeftLink = "timeline_leftlink";
|
||||
static const char* kTimelineRightLink = "timeline_rightlink";
|
||||
static const char* kTimelineBothLinks = "timeline_bothlinks";
|
||||
static const char* kTimelineGear = "timeline_gear";
|
||||
static const char* kTimelineOnionskin = "timeline_onionskin";
|
||||
static const char* kTimelineOnionskinRange = "timeline_onionskin_range";
|
||||
@ -117,6 +122,7 @@ enum {
|
||||
A_PART_SEPARATOR,
|
||||
A_PART_HEADER_EYE,
|
||||
A_PART_HEADER_PADLOCK,
|
||||
A_PART_HEADER_CONTINUOUS,
|
||||
A_PART_HEADER_GEAR,
|
||||
A_PART_HEADER_ONIONSKIN,
|
||||
A_PART_HEADER_ONIONSKIN_RANGE_LEFT,
|
||||
@ -126,6 +132,7 @@ enum {
|
||||
A_PART_LAYER,
|
||||
A_PART_LAYER_EYE_ICON,
|
||||
A_PART_LAYER_PADLOCK_ICON,
|
||||
A_PART_LAYER_CONTINUOUS_ICON,
|
||||
A_PART_LAYER_TEXT,
|
||||
A_PART_CEL,
|
||||
A_PART_RANGE_OUTLINE
|
||||
@ -139,12 +146,17 @@ Timeline::Timeline()
|
||||
, m_timelineClosedEyeStyle(get_style(kTimelineClosedEye))
|
||||
, m_timelineOpenPadlockStyle(get_style(kTimelineOpenPadlock))
|
||||
, m_timelineClosedPadlockStyle(get_style(kTimelineClosedPadlock))
|
||||
, m_timelineContinuousStyle(get_style(kTimelineContinuous))
|
||||
, m_timelineDiscontinuousStyle(get_style(kTimelineDiscontinuous))
|
||||
, m_timelineLayerStyle(get_style(kTimelineLayer))
|
||||
, m_timelineEmptyFrameStyle(get_style(kTimelineEmptyFrame))
|
||||
, m_timelineKeyframeStyle(get_style(kTimelineKeyframe))
|
||||
, m_timelineFromLeftStyle(get_style(kTimelineFromLeft))
|
||||
, m_timelineFromRightStyle(get_style(kTimelineFromRight))
|
||||
, m_timelineFromBothStyle(get_style(kTimelineFromBoth))
|
||||
, m_timelineLeftLinkStyle(get_style(kTimelineLeftLink))
|
||||
, m_timelineRightLinkStyle(get_style(kTimelineRightLink))
|
||||
, m_timelineBothLinksStyle(get_style(kTimelineBothLinks))
|
||||
, m_timelineGearStyle(get_style(kTimelineGear))
|
||||
, m_timelineOnionskinStyle(get_style(kTimelineOnionskin))
|
||||
, m_timelineOnionskinRangeStyle(get_style(kTimelineOnionskinRange))
|
||||
@ -387,6 +399,8 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
break;
|
||||
case A_PART_LAYER_PADLOCK_ICON:
|
||||
break;
|
||||
case A_PART_LAYER_CONTINUOUS_ICON:
|
||||
break;
|
||||
case A_PART_CEL: {
|
||||
LayerIndex old_layer = getLayerIndex(m_layer);
|
||||
bool selectCel = (mouseMsg->left()
|
||||
@ -547,6 +561,13 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
break;
|
||||
}
|
||||
|
||||
case A_PART_HEADER_CONTINUOUS: {
|
||||
bool newContinuousState = !allLayersContinuous();
|
||||
for (size_t i=0; i<m_layers.size(); i++)
|
||||
m_layers[i]->setContinuous(newContinuousState);
|
||||
break;
|
||||
}
|
||||
|
||||
case A_PART_HEADER_GEAR: {
|
||||
gfx::Rect gearBounds =
|
||||
getPartBounds(A_PART_HEADER_GEAR).offset(getBounds().getOrigin());
|
||||
@ -623,6 +644,14 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_CONTINUOUS_ICON:
|
||||
if (m_hot_layer == m_clk_layer && validLayer(m_hot_layer)) {
|
||||
Layer* layer = m_layers[m_clk_layer];
|
||||
ASSERT(layer != NULL);
|
||||
layer->setContinuous(!layer->isContinuous());
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_CEL: {
|
||||
// Show the cel pop-up menu.
|
||||
if (mouseMsg->right()) {
|
||||
@ -1095,6 +1124,7 @@ void Timeline::drawHeader(ui::Graphics* g)
|
||||
IDocumentSettings* docSettings = settings->getDocumentSettings(m_document);
|
||||
bool allInvisible = allLayersInvisible();
|
||||
bool allLocked = allLayersLocked();
|
||||
bool allContinuous = allLayersContinuous();
|
||||
|
||||
drawPart(g, getPartBounds(A_PART_HEADER_EYE),
|
||||
NULL,
|
||||
@ -1110,6 +1140,13 @@ void Timeline::drawHeader(ui::Graphics* g)
|
||||
m_hot_part == A_PART_HEADER_PADLOCK,
|
||||
m_clk_part == A_PART_HEADER_PADLOCK);
|
||||
|
||||
drawPart(g, getPartBounds(A_PART_HEADER_CONTINUOUS),
|
||||
NULL,
|
||||
allContinuous ? m_timelineContinuousStyle: m_timelineDiscontinuousStyle,
|
||||
m_clk_part == A_PART_HEADER_CONTINUOUS,
|
||||
m_hot_part == A_PART_HEADER_CONTINUOUS,
|
||||
m_clk_part == A_PART_HEADER_CONTINUOUS);
|
||||
|
||||
drawPart(g, getPartBounds(A_PART_HEADER_GEAR),
|
||||
NULL, m_timelineGearStyle,
|
||||
false,
|
||||
@ -1174,6 +1211,14 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
|
||||
(hotlayer && m_hot_part == A_PART_LAYER_PADLOCK_ICON),
|
||||
(clklayer && m_clk_part == A_PART_LAYER_PADLOCK_ICON));
|
||||
|
||||
// Draw the continuous flag.
|
||||
bounds = getPartBounds(A_PART_LAYER_CONTINUOUS_ICON, layerIdx);
|
||||
drawPart(g, bounds, NULL,
|
||||
layer->isContinuous() ? m_timelineContinuousStyle: m_timelineDiscontinuousStyle,
|
||||
is_active,
|
||||
(hotlayer && m_hot_part == A_PART_LAYER_CONTINUOUS_ICON),
|
||||
(clklayer && m_clk_part == A_PART_LAYER_CONTINUOUS_ICON));
|
||||
|
||||
// Draw the layer's name.
|
||||
bounds = getPartBounds(A_PART_LAYER_TEXT, layerIdx);
|
||||
drawPart(g, bounds, layer->name().c_str(), m_timelineLayerStyle,
|
||||
@ -1193,6 +1238,7 @@ void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx)
|
||||
|
||||
void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Cel* cel)
|
||||
{
|
||||
Layer* layer = m_layers[layerIndex];
|
||||
Image* image = (cel ? cel->image(): NULL);
|
||||
bool is_hover = (m_hot_part == A_PART_CEL &&
|
||||
m_hot_layer == layerIndex &&
|
||||
@ -1204,23 +1250,24 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
|
||||
if (!clip)
|
||||
return;
|
||||
|
||||
if (layerIndex == getLayerIndex(m_layer) && frame == m_frame)
|
||||
if (layer == m_layer && frame == m_frame)
|
||||
drawPart(g, bounds, NULL, m_timelineSelectedCelStyle, false, false, true);
|
||||
else
|
||||
drawPart(g, bounds, NULL, m_timelineBoxStyle, is_active, is_hover);
|
||||
|
||||
skin::Style* style;
|
||||
bool fromLeft = false;
|
||||
bool fromRight = false;
|
||||
if (is_empty) {
|
||||
style = m_timelineEmptyFrameStyle;
|
||||
}
|
||||
else {
|
||||
Layer* layer = m_layers[layerIndex];
|
||||
Cel* left = (layer->isImage() ? layer->cel(frame-1): NULL);
|
||||
Cel* right = (layer->isImage() ? layer->cel(frame+1): NULL);
|
||||
ObjectId leftImg = (left ? left->image()->id(): 0);
|
||||
ObjectId rightImg = (right ? right->image()->id(): 0);
|
||||
bool fromLeft = (leftImg == cel->image()->id());
|
||||
bool fromRight = (rightImg == cel->image()->id());
|
||||
fromLeft = (leftImg == cel->image()->id());
|
||||
fromRight = (rightImg == cel->image()->id());
|
||||
|
||||
if (fromLeft && fromRight)
|
||||
style = m_timelineFromBothStyle;
|
||||
@ -1232,6 +1279,56 @@ void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, frame_t frame, Ce
|
||||
style = m_timelineKeyframeStyle;
|
||||
}
|
||||
drawPart(g, bounds, NULL, style, is_active, is_hover);
|
||||
|
||||
// Draw decorators to link the activeCel with its links.
|
||||
if (layer == m_layer) {
|
||||
Cel* activeCel = m_layer->cel(m_frame);
|
||||
if (activeCel)
|
||||
drawCelLinkDecorators(g, bounds, cel, activeCel, frame, is_active, is_hover);
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
Cel* cel, Cel* activeCel, frame_t frame, bool is_active, bool is_hover)
|
||||
{
|
||||
ObjectId imageId = activeCel->image()->id();
|
||||
|
||||
// Link in some cel at the left side
|
||||
bool left = false;
|
||||
for (frame_t fr=frame-1; fr>=0; --fr) {
|
||||
Cel* c = m_layer->cel(fr);
|
||||
if (c && c->image()->id() == imageId) {
|
||||
left = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Link in some cel at the right side
|
||||
bool right = false;
|
||||
for (frame_t fr=frame+1; fr<m_sprite->totalFrames(); ++fr) {
|
||||
Cel* c = m_layer->cel(fr);
|
||||
if (c && c->image()->id() == imageId) {
|
||||
right = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cel || cel->image()->id() != imageId) {
|
||||
if (left && right)
|
||||
drawPart(g, bounds, NULL, m_timelineBothLinksStyle, is_active, is_hover);
|
||||
}
|
||||
else {
|
||||
if (left) {
|
||||
Cel* prevCel = m_layer->cel(cel->frame()-1);
|
||||
if (!prevCel || prevCel->image()->id() != imageId)
|
||||
drawPart(g, bounds, NULL, m_timelineLeftLinkStyle, is_active, is_hover);
|
||||
}
|
||||
if (right) {
|
||||
Cel* nextCel = m_layer->cel(cel->frame()+1);
|
||||
if (!nextCel || nextCel->image()->id() != imageId)
|
||||
drawPart(g, bounds, NULL, m_timelineRightLinkStyle, is_active, is_hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::drawLoopRange(ui::Graphics* g)
|
||||
@ -1421,15 +1518,18 @@ gfx::Rect Timeline::getPartBounds(int part, LayerIndex layer, frame_t frame) con
|
||||
case A_PART_HEADER_PADLOCK:
|
||||
return gfx::Rect(FRMSIZE*1, 0, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_GEAR:
|
||||
case A_PART_HEADER_CONTINUOUS:
|
||||
return gfx::Rect(FRMSIZE*2, 0, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_ONIONSKIN:
|
||||
case A_PART_HEADER_GEAR:
|
||||
return gfx::Rect(FRMSIZE*3, 0, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_ONIONSKIN:
|
||||
return gfx::Rect(FRMSIZE*4, 0, FRMSIZE, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_LAYER:
|
||||
return gfx::Rect(FRMSIZE*4, 0,
|
||||
m_separator_x - FRMSIZE*4, HDRSIZE);
|
||||
return gfx::Rect(FRMSIZE*5, 0,
|
||||
m_separator_x - FRMSIZE*5, HDRSIZE);
|
||||
|
||||
case A_PART_HEADER_FRAME:
|
||||
if (validFrame(frame)) {
|
||||
@ -1462,9 +1562,17 @@ gfx::Rect Timeline::getPartBounds(int part, LayerIndex layer, frame_t frame) con
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_CONTINUOUS_ICON:
|
||||
if (validLayer(layer)) {
|
||||
return gfx::Rect(2*FRMSIZE,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
FRMSIZE, LAYSIZE);
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_TEXT:
|
||||
if (validLayer(layer)) {
|
||||
int x = FRMSIZE*2;
|
||||
int x = FRMSIZE*3;
|
||||
return gfx::Rect(x,
|
||||
HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y,
|
||||
m_separator_x - x, LAYSIZE);
|
||||
@ -1605,6 +1713,8 @@ void Timeline::updateHot(ui::Message* msg, const gfx::Point& mousePos, int& hot_
|
||||
hot_part = A_PART_HEADER_EYE;
|
||||
else if (getPartBounds(A_PART_HEADER_PADLOCK).contains(mousePos))
|
||||
hot_part = A_PART_HEADER_PADLOCK;
|
||||
else if (getPartBounds(A_PART_HEADER_CONTINUOUS).contains(mousePos))
|
||||
hot_part = A_PART_HEADER_CONTINUOUS;
|
||||
else if (getPartBounds(A_PART_HEADER_GEAR).contains(mousePos))
|
||||
hot_part = A_PART_HEADER_GEAR;
|
||||
else if (getPartBounds(A_PART_HEADER_ONIONSKIN).contains(mousePos))
|
||||
@ -1623,6 +1733,8 @@ void Timeline::updateHot(ui::Message* msg, const gfx::Point& mousePos, int& hot_
|
||||
hot_part = A_PART_LAYER_EYE_ICON;
|
||||
else if (getPartBounds(A_PART_LAYER_PADLOCK_ICON, hot_layer).contains(mousePos))
|
||||
hot_part = A_PART_LAYER_PADLOCK_ICON;
|
||||
else if (getPartBounds(A_PART_LAYER_CONTINUOUS_ICON, hot_layer).contains(mousePos))
|
||||
hot_part = A_PART_LAYER_CONTINUOUS_ICON;
|
||||
else if (getPartBounds(A_PART_LAYER_TEXT, hot_layer).contains(mousePos))
|
||||
hot_part = A_PART_LAYER_TEXT;
|
||||
else
|
||||
@ -1768,6 +1880,16 @@ void Timeline::updateStatusBar(ui::Message* msg)
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_LAYER_CONTINUOUS_ICON:
|
||||
if (layer != NULL) {
|
||||
sb->setStatusText(0, "Layer '%s' is %s (%s)",
|
||||
layer->name().c_str(),
|
||||
layer->isContinuous() ? "continuous": "discontinuous",
|
||||
layer->isContinuous() ? "prefer linked cels/frames": "prefer individual cels/frames");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case A_PART_HEADER_FRAME:
|
||||
if (validFrame(m_hot_frame)) {
|
||||
sb->setStatusText(0,
|
||||
@ -1782,9 +1904,16 @@ void Timeline::updateStatusBar(ui::Message* msg)
|
||||
if (layer) {
|
||||
Cel* cel = (layer->isImage() ? layer->cel(m_hot_frame): NULL);
|
||||
StatusBar::instance()->setStatusText(0,
|
||||
"%s at frame %d",
|
||||
cel ? "Cel": "Empty cel",
|
||||
(int)m_hot_frame+1);
|
||||
"%s at frame %d"
|
||||
#ifdef _DEBUG
|
||||
" (Image %d)"
|
||||
#endif
|
||||
, cel ? "Cel": "Empty cel"
|
||||
, (int)m_hot_frame+1
|
||||
#ifdef _DEBUG
|
||||
, (cel ? cel->image()->id(): 0)
|
||||
#endif
|
||||
);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -1900,6 +2029,24 @@ bool Timeline::allLayersUnlocked()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Timeline::allLayersContinuous()
|
||||
{
|
||||
for (size_t i=0; i<m_layers.size(); i++)
|
||||
if (!m_layers[i]->isContinuous())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Timeline::allLayersDiscontinuous()
|
||||
{
|
||||
for (size_t i=0; i<m_layers.size(); i++)
|
||||
if (m_layers[i]->isContinuous())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LayerIndex Timeline::getLayerIndex(const Layer* layer) const
|
||||
{
|
||||
for (int i=0; i<(int)m_layers.size(); i++)
|
||||
|
@ -142,6 +142,8 @@ namespace app {
|
||||
bool allLayersInvisible();
|
||||
bool allLayersLocked();
|
||||
bool allLayersUnlocked();
|
||||
bool allLayersContinuous();
|
||||
bool allLayersDiscontinuous();
|
||||
void detachDocument();
|
||||
void setCursor(ui::Message* msg, const gfx::Point& mousePos);
|
||||
void getDrawableLayers(ui::Graphics* g, LayerIndex* first_layer, LayerIndex* last_layer);
|
||||
@ -153,6 +155,8 @@ namespace app {
|
||||
void drawHeaderFrame(ui::Graphics* g, frame_t frame);
|
||||
void drawLayer(ui::Graphics* g, LayerIndex layerIdx);
|
||||
void drawCel(ui::Graphics* g, LayerIndex layerIdx, frame_t frame, Cel* cel);
|
||||
void drawCelLinkDecorators(ui::Graphics* g, const gfx::Rect& bounds,
|
||||
Cel* cel, Cel* activeCel, frame_t frame, bool is_active, bool is_hover);
|
||||
void drawLoopRange(ui::Graphics* g);
|
||||
void drawRangeOutline(ui::Graphics* g);
|
||||
void drawPaddings(ui::Graphics* g);
|
||||
@ -201,12 +205,17 @@ namespace app {
|
||||
skin::Style* m_timelineClosedEyeStyle;
|
||||
skin::Style* m_timelineOpenPadlockStyle;
|
||||
skin::Style* m_timelineClosedPadlockStyle;
|
||||
skin::Style* m_timelineContinuousStyle;
|
||||
skin::Style* m_timelineDiscontinuousStyle;
|
||||
skin::Style* m_timelineLayerStyle;
|
||||
skin::Style* m_timelineEmptyFrameStyle;
|
||||
skin::Style* m_timelineKeyframeStyle;
|
||||
skin::Style* m_timelineFromLeftStyle;
|
||||
skin::Style* m_timelineFromRightStyle;
|
||||
skin::Style* m_timelineFromBothStyle;
|
||||
skin::Style* m_timelineLeftLinkStyle;
|
||||
skin::Style* m_timelineRightLinkStyle;
|
||||
skin::Style* m_timelineBothLinksStyle;
|
||||
skin::Style* m_timelineGearStyle;
|
||||
skin::Style* m_timelineOnionskinStyle;
|
||||
skin::Style* m_timelineOnionskinRangeStyle;
|
||||
|
@ -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,10 +56,25 @@ void Cel::setFrame(frame_t frame)
|
||||
m_frame = frame;
|
||||
}
|
||||
|
||||
void Cel::setImage(const ImageRef& image)
|
||||
void Cel::setDataRef(const CelDataRef& celData)
|
||||
{
|
||||
m_image = image;
|
||||
fixupImage();
|
||||
ASSERT(celData);
|
||||
m_data = celData;
|
||||
}
|
||||
|
||||
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
|
||||
@ -73,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;
|
||||
}
|
||||
}
|
||||
@ -87,13 +112,27 @@ Cel* Cel::link() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t Cel::links() const
|
||||
{
|
||||
size_t links = 0;
|
||||
|
||||
Sprite* sprite = this->sprite();
|
||||
for (frame_t fr=0; fr<sprite->totalFrames(); ++fr) {
|
||||
Cel* cel = m_layer->cel(fr);
|
||||
if (cel && cel != this && cel->dataRef().get() == m_data.get())
|
||||
++links;
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
gfx::Rect Cel::bounds() const
|
||||
{
|
||||
Image* image = this->image();
|
||||
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();
|
||||
@ -108,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,37 +25,39 @@ 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;
|
||||
size_t links() const;
|
||||
gfx::Rect bounds() const;
|
||||
|
||||
// You should change the frame only if the cel isn't member of a
|
||||
// layer. If the cel is already in a layer, you should use
|
||||
// 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);
|
||||
@ -63,9 +67,10 @@ namespace doc {
|
||||
|
||||
LayerImage* m_layer;
|
||||
frame_t m_frame; // Frame position
|
||||
ImageRef m_image;
|
||||
gfx::Point m_position; // X/Y screen position
|
||||
int m_opacity; // Opacity level
|
||||
CelDataRef m_data;
|
||||
|
||||
Cel();
|
||||
DISABLE_COPYING(Cel);
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
43
src/doc/cel_data.cpp
Normal file
43
src/doc/cel_data.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/cel_data.h"
|
||||
|
||||
#include "gfx/rect.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
CelData::CelData(const ImageRef& image)
|
||||
: Object(ObjectType::CelData)
|
||||
, m_image(image)
|
||||
, m_position(0, 0)
|
||||
, m_opacity(255)
|
||||
{
|
||||
}
|
||||
|
||||
CelData::CelData(const CelData& celData)
|
||||
: Object(ObjectType::CelData)
|
||||
, m_image(celData.m_image)
|
||||
, m_position(celData.m_position)
|
||||
, m_opacity(celData.m_opacity)
|
||||
{
|
||||
}
|
||||
|
||||
void CelData::setImage(const ImageRef& image)
|
||||
{
|
||||
ASSERT(image.get());
|
||||
|
||||
m_image = image;
|
||||
}
|
||||
|
||||
} // namespace doc
|
50
src/doc/cel_data.h
Normal file
50
src/doc/cel_data.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_CEL_DATA_H_INCLUDED
|
||||
#define DOC_CEL_DATA_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/shared_ptr.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "doc/object.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
class CelData : public Object {
|
||||
public:
|
||||
CelData(const ImageRef& image);
|
||||
CelData(const CelData& celData);
|
||||
|
||||
const gfx::Point& position() const { return m_position; }
|
||||
int opacity() const { return m_opacity; }
|
||||
Image* image() const { return const_cast<Image*>(m_image.get()); };
|
||||
ImageRef imageRef() const { return m_image; }
|
||||
|
||||
void setImage(const ImageRef& image);
|
||||
void setPosition(int x, int y) {
|
||||
m_position.x = x;
|
||||
m_position.y = y;
|
||||
}
|
||||
void setPosition(const gfx::Point& pos) { m_position = pos; }
|
||||
void setOpacity(int opacity) { m_opacity = opacity; }
|
||||
|
||||
virtual int getMemSize() const override {
|
||||
ASSERT(m_image);
|
||||
return sizeof(CelData) + m_image->getMemSize();
|
||||
}
|
||||
|
||||
private:
|
||||
ImageRef m_image;
|
||||
gfx::Point m_position; // X/Y screen position
|
||||
int m_opacity; // Opacity level
|
||||
};
|
||||
|
||||
typedef SharedPtr<CelData> CelDataRef;
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
51
src/doc/cel_data_io.cpp
Normal file
51
src/doc/cel_data_io.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/cel_data_io.h"
|
||||
|
||||
#include "base/serialization.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "doc/cel_data.h"
|
||||
#include "doc/subobjects_io.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace doc {
|
||||
|
||||
using namespace base::serialization;
|
||||
using namespace base::serialization::little_endian;
|
||||
|
||||
void write_celdata(std::ostream& os, CelData* celdata)
|
||||
{
|
||||
write32(os, celdata->id());
|
||||
write16(os, (int16_t)celdata->position().x);
|
||||
write16(os, (int16_t)celdata->position().y);
|
||||
write8(os, celdata->opacity());
|
||||
write32(os, celdata->image()->id());
|
||||
}
|
||||
|
||||
CelData* read_celdata(std::istream& is, SubObjectsIO* subObjects)
|
||||
{
|
||||
ObjectId id = read32(is);
|
||||
int x = (int16_t)read16(is);
|
||||
int y = (int16_t)read16(is);
|
||||
int opacity = read8(is);
|
||||
|
||||
ObjectId imageId = read32(is);
|
||||
ImageRef image(subObjects->getImageRef(imageId));
|
||||
|
||||
base::UniquePtr<CelData> celdata(new CelData(image));
|
||||
celdata->setPosition(x, y);
|
||||
celdata->setOpacity(opacity);
|
||||
celdata->setId(id);
|
||||
return celdata.release();
|
||||
}
|
||||
|
||||
}
|
23
src/doc/cel_data_io.h
Normal file
23
src/doc/cel_data_io.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_CEL_DATA_IO_H_INCLUDED
|
||||
#define DOC_CEL_DATA_IO_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace doc {
|
||||
|
||||
class CelData;
|
||||
class SubObjectsIO;
|
||||
|
||||
void write_celdata(std::ostream& os, CelData* cel);
|
||||
CelData* read_celdata(std::istream& is, SubObjectsIO* subObjects);
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
@ -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,41 +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)
|
||||
{
|
||||
Cel* link = cel->link();
|
||||
|
||||
write32(os, cel->id());
|
||||
write16(os, cel->frame());
|
||||
write16(os, (int16_t)cel->x());
|
||||
write16(os, (int16_t)cel->y());
|
||||
write16(os, cel->opacity());
|
||||
write16(os, link ? 1: 0);
|
||||
if (link)
|
||||
write32(os, link->id());
|
||||
else
|
||||
subObjects->write_image(os, cel->image());
|
||||
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 = read16(is);
|
||||
bool is_link = (read16(is) == 1);
|
||||
|
||||
base::UniquePtr<Cel> cel(new Cel(frame, ImageRef(NULL)));
|
||||
|
||||
cel->setPosition(x, y);
|
||||
cel->setOpacity(opacity);
|
||||
|
||||
if (is_link) {
|
||||
ObjectId imageId = read32(is);
|
||||
cel->setImage(sprite->getImage(imageId));
|
||||
}
|
||||
else
|
||||
cel->setImage(ImageRef(subObjects->read_image(is)));
|
||||
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
|
||||
|
||||
|
84
src/doc/cels_range.cpp
Normal file
84
src/doc/cels_range.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/cels_range.h"
|
||||
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
CelsRange::CelsRange(const Sprite* sprite,
|
||||
frame_t first, frame_t last, Flags flags)
|
||||
: m_begin(sprite, first, last, flags)
|
||||
, m_end()
|
||||
{
|
||||
}
|
||||
|
||||
CelsRange::iterator::iterator()
|
||||
: m_cel(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CelsRange::iterator::iterator(const Sprite* sprite, frame_t first, frame_t last, CelsRange::Flags flags)
|
||||
: m_cel(nullptr)
|
||||
, m_first(first)
|
||||
, m_last(last)
|
||||
, m_flags(flags)
|
||||
{
|
||||
// Get first cel
|
||||
Layer* layer = sprite->layer(sprite->firstLayer());
|
||||
while (layer && !m_cel) {
|
||||
for (frame_t f=first; f<=last; ++f) {
|
||||
m_cel = layer->cel(f);
|
||||
if (m_cel)
|
||||
break;
|
||||
m_cel = nullptr;
|
||||
}
|
||||
layer = layer->getNext();
|
||||
}
|
||||
if (m_cel && flags == CelsRange::UNIQUE)
|
||||
m_visited.insert(m_cel->data()->id());
|
||||
}
|
||||
|
||||
CelsRange::iterator& CelsRange::iterator::operator++()
|
||||
{
|
||||
if (!m_cel)
|
||||
return *this;
|
||||
|
||||
// Get next cel
|
||||
Layer* layer = m_cel->layer();
|
||||
frame_t first = m_cel->frame()+1;
|
||||
m_cel = nullptr;
|
||||
|
||||
while (layer && !m_cel) {
|
||||
for (frame_t f=first; f<=m_last; ++f) {
|
||||
m_cel = layer->cel(f);
|
||||
if (m_cel) {
|
||||
if (m_flags == CelsRange::UNIQUE) {
|
||||
if (m_visited.find(m_cel->data()->id()) == m_visited.end()) {
|
||||
m_visited.insert(m_cel->data()->id());
|
||||
break;
|
||||
}
|
||||
else
|
||||
m_cel = nullptr;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
layer = layer->getNext();
|
||||
first = m_first;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace doc
|
66
src/doc/cels_range.h
Normal file
66
src/doc/cels_range.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_CELS_RANGE_H_INCLUDED
|
||||
#define DOC_CELS_RANGE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/frame.h"
|
||||
#include "doc/object_id.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace doc {
|
||||
class Cel;
|
||||
class Sprite;
|
||||
|
||||
class CelsRange {
|
||||
public:
|
||||
enum Flags {
|
||||
ALL,
|
||||
UNIQUE,
|
||||
};
|
||||
|
||||
CelsRange(const Sprite* sprite,
|
||||
frame_t first, frame_t last, Flags flags = ALL);
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
iterator();
|
||||
iterator(const Sprite* sprite, frame_t first, frame_t last, Flags flags);
|
||||
|
||||
bool operator==(const iterator& other) const {
|
||||
return m_cel == other.m_cel;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
Cel* operator*() const {
|
||||
return m_cel;
|
||||
}
|
||||
|
||||
iterator& operator++();
|
||||
|
||||
private:
|
||||
Cel* m_cel;
|
||||
frame_t m_first, m_last;
|
||||
Flags m_flags;
|
||||
std::set<ObjectId> m_visited;
|
||||
};
|
||||
|
||||
iterator begin() { return m_begin; }
|
||||
iterator end() { return m_end; }
|
||||
|
||||
private:
|
||||
iterator m_begin, m_end;
|
||||
Flags m_flags;
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
@ -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();
|
||||
|
||||
|
@ -33,6 +33,7 @@ namespace doc {
|
||||
Editable = 2, // Can be written
|
||||
LockMove = 4, // Cannot be moved
|
||||
Background = 8, // Stack order cannot be changed
|
||||
Continuous = 16, // Prefer to link cels when the user copy them
|
||||
|
||||
BackgroundLayerFlags = LockMove | Background,
|
||||
};
|
||||
@ -64,11 +65,13 @@ namespace doc {
|
||||
bool isVisible() const { return hasFlags(LayerFlags::Visible); }
|
||||
bool isEditable() const { return hasFlags(LayerFlags::Editable); }
|
||||
bool isMovable() const { return !hasFlags(LayerFlags::LockMove); }
|
||||
bool isContinuous() const { return hasFlags(LayerFlags::Continuous); }
|
||||
|
||||
void setBackground(bool state) { switchFlags(LayerFlags::Background, state); }
|
||||
void setVisible (bool state) { switchFlags(LayerFlags::Visible, state); }
|
||||
void setEditable (bool state) { switchFlags(LayerFlags::Editable, state); }
|
||||
void setMovable (bool state) { switchFlags(LayerFlags::LockMove, !state); }
|
||||
void setContinuous(bool state) { switchFlags(LayerFlags::Continuous, state); }
|
||||
|
||||
LayerFlags flags() const {
|
||||
return m_flags;
|
||||
|
@ -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
|
||||
@ -41,15 +48,39 @@ void write_layer(std::ostream& os, SubObjectsIO* subObjects, Layer* layer)
|
||||
switch (layer->type()) {
|
||||
|
||||
case ObjectType::LayerImage: {
|
||||
// Number of cels
|
||||
write16(os, static_cast<LayerImage*>(layer)->getCelsCount());
|
||||
|
||||
CelIterator it = static_cast<LayerImage*>(layer)->getCelBegin();
|
||||
CelIterator it, begin = static_cast<LayerImage*>(layer)->getCelBegin();
|
||||
CelIterator end = static_cast<LayerImage*>(layer)->getCelEnd();
|
||||
|
||||
for (; it != end; ++it) {
|
||||
// Images
|
||||
int images = 0;
|
||||
int celdatas = 0;
|
||||
for (it=begin; it != end; ++it) {
|
||||
Cel* cel = *it;
|
||||
subObjects->write_cel(os, cel);
|
||||
if (!cel->link()) {
|
||||
++images;
|
||||
++celdatas;
|
||||
}
|
||||
}
|
||||
|
||||
write16(os, images);
|
||||
for (it=begin; it != end; ++it) {
|
||||
Cel* cel = *it;
|
||||
if (!cel->link())
|
||||
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;
|
||||
write_cel(os, cel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -62,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) {
|
||||
@ -89,13 +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(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);
|
||||
@ -105,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
|
||||
@ -124,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"
|
||||
@ -208,6 +209,16 @@ LayerIndex Sprite::countLayers() const
|
||||
return LayerIndex(folder()->getLayersCount());
|
||||
}
|
||||
|
||||
LayerIndex Sprite::firstLayer() const
|
||||
{
|
||||
return LayerIndex(0);
|
||||
}
|
||||
|
||||
LayerIndex Sprite::lastLayer() const
|
||||
{
|
||||
return LayerIndex(folder()->getLayersCount()-1);
|
||||
}
|
||||
|
||||
Layer* Sprite::layer(int layerIndex) const
|
||||
{
|
||||
return indexToLayer(LayerIndex(layerIndex));
|
||||
@ -397,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)
|
||||
@ -453,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) {
|
||||
@ -524,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;
|
||||
@ -78,6 +80,8 @@ namespace doc {
|
||||
LayerImage* backgroundLayer() const;
|
||||
|
||||
LayerIndex countLayers() const;
|
||||
LayerIndex firstLayer() const;
|
||||
LayerIndex lastLayer() const;
|
||||
|
||||
Layer* layer(int layerIndex) const;
|
||||
Layer* indexToLayer(LayerIndex index) const;
|
||||
@ -115,18 +119,23 @@ namespace doc {
|
||||
void setFrameRangeDuration(frame_t from, frame_t to, int msecs);
|
||||
void setDurationForAllFrames(int msecs);
|
||||
|
||||
////////////////////////////////////////
|
||||
// Shared Images and CelData (for linked Cels)
|
||||
|
||||
ImageRef getImageRef(ObjectId imageId);
|
||||
CelDataRef getCelDataRef(ObjectId celDataId);
|
||||
|
||||
////////////////////////////////////////
|
||||
// Images
|
||||
|
||||
ImageRef getImage(ObjectId imageId);
|
||||
void replaceImage(ObjectId curImageId, const ImageRef& newImage);
|
||||
void getCels(CelList& cels) const;
|
||||
void getImages(std::vector<Image*>& images) const;
|
||||
void remapImages(frame_t frameFrom, frame_t frameTo, const std::vector<uint8_t>& mapping);
|
||||
void pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const;
|
||||
|
||||
// Returns the list of cels in the given frame
|
||||
CelList cels(frame_t frame) const;
|
||||
CelsRange cels() const;
|
||||
CelsRange cels(frame_t frame) const;
|
||||
CelsRange uniqueCels() const;
|
||||
|
||||
private:
|
||||
Document* m_document;
|
||||
|
108
src/doc/sprite_tests.cpp
Normal file
108
src/doc/sprite_tests.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "doc/cel.h"
|
||||
#include "doc/cels_range.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/pixel_format.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
using namespace doc;
|
||||
|
||||
// lay1 = A _ B
|
||||
// lay2 = C D E
|
||||
TEST(Sprite, CelsRange)
|
||||
{
|
||||
Sprite* spr = new Sprite(IMAGE_RGB, 32, 32, 256);
|
||||
spr->setTotalFrames(3);
|
||||
|
||||
LayerImage* lay1 = new LayerImage(spr);
|
||||
LayerImage* lay2 = new LayerImage(spr);
|
||||
spr->folder()->addLayer(lay1);
|
||||
spr->folder()->addLayer(lay2);
|
||||
|
||||
ImageRef imgA(Image::create(IMAGE_RGB, 32, 32));
|
||||
Cel* celA = new Cel(frame_t(0), imgA);
|
||||
Cel* celB = Cel::createLink(celA);
|
||||
celB->setFrame(frame_t(2));
|
||||
lay1->addCel(celA);
|
||||
lay1->addCel(celB);
|
||||
|
||||
ImageRef imgC(Image::create(IMAGE_RGB, 32, 32));
|
||||
Cel* celC = new Cel(frame_t(0), imgC);
|
||||
Cel* celD = Cel::createCopy(celC);
|
||||
Cel* celE = Cel::createLink(celD);
|
||||
celD->setFrame(frame_t(1));
|
||||
celE->setFrame(frame_t(2));
|
||||
lay2->addCel(celC);
|
||||
lay2->addCel(celD);
|
||||
lay2->addCel(celE);
|
||||
|
||||
int i = 0;
|
||||
for (Cel* cel : spr->cels()) {
|
||||
switch (i) {
|
||||
case 0: EXPECT_EQ(cel, celA); break;
|
||||
case 1: EXPECT_EQ(cel, celB); break;
|
||||
case 2: EXPECT_EQ(cel, celC); break;
|
||||
case 3: EXPECT_EQ(cel, celD); break;
|
||||
case 4: EXPECT_EQ(cel, celE); break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
EXPECT_EQ(5, i);
|
||||
|
||||
i = 0;
|
||||
for (Cel* cel : spr->uniqueCels()) {
|
||||
switch (i) {
|
||||
case 0: EXPECT_EQ(cel, celA); break;
|
||||
case 1: EXPECT_EQ(cel, celC); break;
|
||||
case 2: EXPECT_EQ(cel, celD); break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
EXPECT_EQ(3, i);
|
||||
|
||||
i = 0;
|
||||
for (Cel* cel : spr->cels(frame_t(0))) {
|
||||
switch (i) {
|
||||
case 0: EXPECT_EQ(cel, celA); break;
|
||||
case 1: EXPECT_EQ(cel, celC); break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
EXPECT_EQ(2, i);
|
||||
|
||||
i = 0;
|
||||
for (Cel* cel : spr->cels(frame_t(1))) {
|
||||
switch (i) {
|
||||
case 0: EXPECT_EQ(cel, celD); break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
EXPECT_EQ(1, i);
|
||||
|
||||
i = 0;
|
||||
for (Cel* cel : spr->cels(frame_t(2))) {
|
||||
switch (i) {
|
||||
case 0: EXPECT_EQ(cel, celB); break;
|
||||
case 1: EXPECT_EQ(cel, celE); break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
EXPECT_EQ(2, i);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
70
src/doc/subobjects_io.cpp
Normal file
70
src/doc/subobjects_io.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/subobjects_io.h"
|
||||
|
||||
#include "doc/cel.h"
|
||||
#include "doc/cel_io.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/image_io.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/layer_io.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
SubObjectsIO::SubObjectsIO(Sprite* sprite)
|
||||
: m_sprite(sprite)
|
||||
{
|
||||
}
|
||||
|
||||
void SubObjectsIO::addImageRef(const ImageRef& image)
|
||||
{
|
||||
ASSERT(image);
|
||||
ASSERT(!getImageRef(image->id()));
|
||||
m_images.insert(std::make_pair(image->id(), image));
|
||||
}
|
||||
|
||||
ImageRef SubObjectsIO::getImageRef(ObjectId imageId)
|
||||
{
|
||||
auto it = m_images.find(imageId);
|
||||
if (it != m_images.end()) {
|
||||
ImageRef image = it->second;
|
||||
ASSERT(image->id() == imageId);
|
||||
ASSERT(!m_sprite->getImageRef(imageId));
|
||||
return image;
|
||||
}
|
||||
else
|
||||
return m_sprite->getImageRef(imageId);
|
||||
}
|
||||
|
||||
void SubObjectsIO::addCelDataRef(const CelDataRef& celdata)
|
||||
{
|
||||
ASSERT(celdata);
|
||||
ASSERT(!getCelDataRef(celdata->id()));
|
||||
m_celdatas.insert(std::make_pair(celdata->id(), celdata));
|
||||
}
|
||||
|
||||
CelDataRef SubObjectsIO::getCelDataRef(ObjectId celdataId)
|
||||
{
|
||||
auto it = m_celdatas.find(celdataId);
|
||||
if (it != m_celdatas.end()) {
|
||||
CelDataRef celdata = it->second;
|
||||
ASSERT(celdata->id() == celdataId);
|
||||
ASSERT(!m_sprite->getCelDataRef(celdataId));
|
||||
return celdata;
|
||||
}
|
||||
else
|
||||
return m_sprite->getCelDataRef(celdataId);
|
||||
}
|
||||
|
||||
} // namespace doc
|
@ -8,28 +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);
|
||||
|
||||
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
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace render {
|
||||
|
||||
@ -49,7 +50,6 @@ Palette* create_palette_from_rgb(
|
||||
palette = new Palette(frame_t(0), 256);
|
||||
|
||||
bool has_background_layer = (sprite->backgroundLayer() != NULL);
|
||||
Image* flat_image;
|
||||
|
||||
ImagesCollector images(
|
||||
sprite->folder(), // All layers
|
||||
@ -58,24 +58,29 @@ Palette* create_palette_from_rgb(
|
||||
false); // forWrite=false, read only
|
||||
|
||||
// Add a flat image with the current sprite's frame rendered
|
||||
flat_image = Image::create(sprite->pixelFormat(),
|
||||
sprite->width(), sprite->height());
|
||||
ImageRef flat_image(Image::create(sprite->pixelFormat(),
|
||||
sprite->width(), sprite->height()));
|
||||
|
||||
render::Render().renderSprite(flat_image, sprite, frameNumber);
|
||||
|
||||
// Create an array of images
|
||||
size_t nimage = images.size() + 1; // +1 for flat_image
|
||||
std::vector<Image*> image_array(nimage);
|
||||
std::vector<Image*> image_array;
|
||||
std::map<ObjectId, Image*> used_images;
|
||||
|
||||
size_t c = 0;
|
||||
for (ImagesCollector::ItemsIterator it=images.begin(); it!=images.end(); ++it)
|
||||
image_array[c++] = it->image();
|
||||
image_array[c++] = flat_image; // The 'flat_image'
|
||||
for (auto it=images.begin(); it!=images.end(); ++it) {
|
||||
Image* image = it->image();
|
||||
ObjectId imageId = image->id();
|
||||
|
||||
if (used_images.find(imageId) == used_images.end()) {
|
||||
used_images.insert(std::make_pair(imageId, image));
|
||||
image_array.push_back(image);
|
||||
}
|
||||
}
|
||||
image_array.push_back(flat_image);
|
||||
|
||||
// Generate an optimized palette for all images
|
||||
create_palette_from_images(image_array, palette, has_background_layer);
|
||||
|
||||
delete flat_image;
|
||||
return palette;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user