2014-10-21 09:21:31 +08:00
|
|
|
// Aseprite Document Library
|
2015-01-19 09:05:33 +08:00
|
|
|
// Copyright (c) 2001-2015 David Capello
|
2014-10-21 09:21:31 +08:00
|
|
|
//
|
|
|
|
// This file is released under the terms of the MIT license.
|
|
|
|
// Read LICENSE.txt for more information.
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2007-09-19 07:57:02 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/sprite.h"
|
2011-03-25 00:06:40 +08:00
|
|
|
|
2011-01-24 06:19:18 +08:00
|
|
|
#include "base/memory.h"
|
2010-10-01 08:38:01 +08:00
|
|
|
#include "base/remove_from_container.h"
|
2013-03-31 06:53:52 +08:00
|
|
|
#include "base/unique_ptr.h"
|
2015-03-23 23:57:59 +08:00
|
|
|
#include "doc/cel.h"
|
2015-02-09 22:40:43 +08:00
|
|
|
#include "doc/cels_range.h"
|
2015-02-18 03:07:20 +08:00
|
|
|
#include "doc/frame_tag.h"
|
2015-06-13 00:56:18 +08:00
|
|
|
#include "doc/image_impl.h"
|
2015-03-23 23:57:59 +08:00
|
|
|
#include "doc/layer.h"
|
|
|
|
#include "doc/palette.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/primitives.h"
|
2015-03-23 23:57:59 +08:00
|
|
|
#include "doc/remap.h"
|
|
|
|
#include "doc/rgbmap.h"
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-03-23 11:06:43 +08:00
|
|
|
#include <cstring>
|
|
|
|
#include <vector>
|
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
namespace doc {
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
static Layer* index2layer(const Layer* layer, const LayerIndex& index, int* index_count);
|
|
|
|
static LayerIndex layer2index(const Layer* layer, const Layer* find_layer, int* index_count);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2008-10-01 09:27:51 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2011-03-25 00:06:40 +08:00
|
|
|
// Constructors/Destructor
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2012-02-13 10:21:06 +08:00
|
|
|
Sprite::Sprite(PixelFormat format, int width, int height, int ncolors)
|
2014-10-21 09:21:31 +08:00
|
|
|
: Object(ObjectType::Sprite)
|
2015-01-19 09:05:33 +08:00
|
|
|
, m_document(NULL)
|
2012-02-13 10:21:06 +08:00
|
|
|
, m_format(format)
|
2010-03-31 08:43:18 +08:00
|
|
|
, m_width(width)
|
|
|
|
, m_height(height)
|
2012-07-09 08:09:09 +08:00
|
|
|
, m_frames(1)
|
2015-02-17 22:37:42 +08:00
|
|
|
, m_frameTags(this)
|
2008-10-01 09:27:51 +08:00
|
|
|
{
|
2010-08-04 10:33:44 +08:00
|
|
|
ASSERT(width > 0 && height > 0);
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
m_frlens.push_back(100); // First frame with 100 msecs of duration
|
2011-03-25 00:06:40 +08:00
|
|
|
m_folder = new LayerFolder(this);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-03-28 23:15:32 +08:00
|
|
|
// Generate palette
|
2014-12-29 07:39:11 +08:00
|
|
|
Palette pal(frame_t(0), ncolors);
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2012-02-13 10:21:06 +08:00
|
|
|
switch (format) {
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-03-28 23:15:32 +08:00
|
|
|
// For colored images
|
2007-09-19 07:57:02 +08:00
|
|
|
case IMAGE_RGB:
|
|
|
|
case IMAGE_INDEXED:
|
2010-05-30 21:48:37 +08:00
|
|
|
pal.resize(ncolors);
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
|
2010-03-28 23:15:32 +08:00
|
|
|
// For black and white images
|
2007-09-19 07:57:02 +08:00
|
|
|
case IMAGE_GRAYSCALE:
|
|
|
|
case IMAGE_BITMAP:
|
2010-03-28 23:15:32 +08:00
|
|
|
for (int c=0; c<ncolors; c++) {
|
2012-01-06 06:45:03 +08:00
|
|
|
int g = 255 * c / (ncolors-1);
|
|
|
|
g = MID(0, g, 255);
|
2013-11-10 06:59:05 +08:00
|
|
|
pal.setEntry(c, rgba(g, g, g, 255));
|
2010-03-28 23:15:32 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-04-21 10:44:31 +08:00
|
|
|
// Initial RGB map
|
|
|
|
m_rgbMap = NULL;
|
|
|
|
|
2011-01-21 04:17:35 +08:00
|
|
|
// The transparent color for indexed images is 0 by default
|
|
|
|
m_transparentColor = 0;
|
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
setPalette(&pal, true);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
Sprite::~Sprite()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-03-31 08:43:18 +08:00
|
|
|
// Destroy layers
|
|
|
|
delete m_folder;
|
2008-10-01 09:27:51 +08:00
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
// Destroy palettes
|
2010-10-01 08:38:01 +08:00
|
|
|
{
|
|
|
|
PalettesList::iterator end = m_palettes.end();
|
|
|
|
PalettesList::iterator it = m_palettes.begin();
|
|
|
|
for (; it != end; ++it)
|
2012-01-06 06:45:03 +08:00
|
|
|
delete *it; // palette
|
2008-10-01 09:27:51 +08:00
|
|
|
}
|
|
|
|
|
2011-03-23 11:06:43 +08:00
|
|
|
// Destroy RGB map
|
2010-04-21 10:44:31 +08:00
|
|
|
delete m_rgbMap;
|
2008-10-01 09:27:51 +08:00
|
|
|
}
|
|
|
|
|
2014-07-29 11:53:24 +08:00
|
|
|
// static
|
2014-10-21 09:21:31 +08:00
|
|
|
Sprite* Sprite::createBasicSprite(doc::PixelFormat format, int width, int height, int ncolors)
|
2014-07-29 11:53:24 +08:00
|
|
|
{
|
|
|
|
// Create the sprite.
|
2014-10-21 09:21:31 +08:00
|
|
|
base::UniquePtr<doc::Sprite> sprite(new doc::Sprite(format, width, height, ncolors));
|
2014-12-29 07:39:11 +08:00
|
|
|
sprite->setTotalFrames(doc::frame_t(1));
|
2014-07-29 11:53:24 +08:00
|
|
|
|
|
|
|
// Create the main image.
|
2015-01-04 21:58:14 +08:00
|
|
|
doc::ImageRef image(doc::Image::create(format, width, height));
|
2015-04-03 07:42:43 +08:00
|
|
|
doc::clear_image(image.get(), 0);
|
2014-07-29 11:53:24 +08:00
|
|
|
|
|
|
|
// Create the first transparent layer.
|
|
|
|
{
|
2014-10-21 09:21:31 +08:00
|
|
|
base::UniquePtr<doc::LayerImage> layer(new doc::LayerImage(sprite));
|
2014-07-29 11:53:24 +08:00
|
|
|
layer->setName("Layer 1");
|
|
|
|
|
|
|
|
// Create the cel.
|
|
|
|
{
|
2015-01-04 21:58:14 +08:00
|
|
|
base::UniquePtr<doc::Cel> cel(new doc::Cel(doc::frame_t(0), image));
|
2014-07-29 11:53:24 +08:00
|
|
|
cel->setPosition(0, 0);
|
|
|
|
|
|
|
|
// Add the cel in the layer.
|
|
|
|
layer->addCel(cel);
|
|
|
|
cel.release(); // Release the cel because it is in the layer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the layer in the sprite.
|
2014-07-30 12:28:15 +08:00
|
|
|
sprite->folder()->addLayer(layer.release()); // Release the layer because it's owned by the sprite
|
2014-07-29 11:53:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return sprite.release();
|
|
|
|
}
|
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Main properties
|
|
|
|
|
2012-02-13 10:21:06 +08:00
|
|
|
void Sprite::setPixelFormat(PixelFormat format)
|
2011-03-25 00:06:40 +08:00
|
|
|
{
|
2012-02-13 10:21:06 +08:00
|
|
|
m_format = format;
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sprite::setSize(int width, int height)
|
|
|
|
{
|
|
|
|
ASSERT(width > 0);
|
|
|
|
ASSERT(height > 0);
|
|
|
|
|
|
|
|
m_width = width;
|
|
|
|
m_height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sprite::needAlpha() const
|
|
|
|
{
|
2012-02-13 10:21:06 +08:00
|
|
|
switch (m_format) {
|
2011-03-25 00:06:40 +08:00
|
|
|
case IMAGE_RGB:
|
2015-04-21 21:01:28 +08:00
|
|
|
case IMAGE_GRAYSCALE: {
|
|
|
|
Layer* bg = backgroundLayer();
|
|
|
|
return (!bg || !bg->isVisible());
|
|
|
|
}
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
|
|
|
return false;
|
2014-08-10 05:04:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Sprite::supportAlpha() const
|
|
|
|
{
|
|
|
|
switch (m_format) {
|
|
|
|
case IMAGE_RGB:
|
|
|
|
case IMAGE_GRAYSCALE:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
|
|
|
|
2014-05-08 11:30:36 +08:00
|
|
|
void Sprite::setTransparentColor(color_t color)
|
2011-03-25 00:06:40 +08:00
|
|
|
{
|
|
|
|
m_transparentColor = color;
|
2014-06-03 11:05:57 +08:00
|
|
|
|
2014-06-10 09:36:42 +08:00
|
|
|
// Change the mask color of all images.
|
2015-01-04 21:58:14 +08:00
|
|
|
std::vector<Image*> images;
|
|
|
|
getImages(images);
|
|
|
|
for (Image* image : images)
|
|
|
|
image->setMaskColor(color);
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int Sprite::getMemSize() const
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2014-06-03 11:05:57 +08:00
|
|
|
int size = 0;
|
2008-03-23 02:43:56 +08:00
|
|
|
|
2015-01-04 21:58:14 +08:00
|
|
|
std::vector<Image*> images;
|
|
|
|
getImages(images);
|
|
|
|
for (Image* image : images)
|
|
|
|
size += image->getRowStrideSize() * image->height();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Layers
|
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
LayerFolder* Sprite::folder() const
|
2011-03-25 00:06:40 +08:00
|
|
|
{
|
|
|
|
return m_folder;
|
|
|
|
}
|
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
LayerImage* Sprite::backgroundLayer() const
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2014-07-30 12:28:15 +08:00
|
|
|
if (folder()->getLayersCount() > 0) {
|
|
|
|
Layer* bglayer = *folder()->getLayerBegin();
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
if (bglayer->isBackground()) {
|
|
|
|
ASSERT(bglayer->isImage());
|
2010-03-31 08:43:18 +08:00
|
|
|
return static_cast<LayerImage*>(bglayer);
|
2010-12-12 23:10:46 +08:00
|
|
|
}
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
|
|
|
return NULL;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
LayerIndex Sprite::countLayers() const
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2014-07-30 12:28:15 +08:00
|
|
|
return LayerIndex(folder()->getLayersCount());
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2015-02-04 19:19:02 +08:00
|
|
|
LayerIndex Sprite::firstLayer() const
|
|
|
|
{
|
|
|
|
return LayerIndex(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerIndex Sprite::lastLayer() const
|
|
|
|
{
|
|
|
|
return LayerIndex(folder()->getLayersCount()-1);
|
|
|
|
}
|
|
|
|
|
2014-12-28 22:06:11 +08:00
|
|
|
Layer* Sprite::layer(int layerIndex) const
|
|
|
|
{
|
|
|
|
return indexToLayer(LayerIndex(layerIndex));
|
|
|
|
}
|
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
Layer* Sprite::indexToLayer(LayerIndex index) const
|
2011-03-25 00:06:40 +08:00
|
|
|
{
|
2014-08-08 07:19:31 +08:00
|
|
|
if (index < LayerIndex(0))
|
|
|
|
return NULL;
|
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
int index_count = -1;
|
2014-07-30 12:28:15 +08:00
|
|
|
return index2layer(folder(), index, &index_count);
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
LayerIndex Sprite::layerToIndex(const Layer* layer) const
|
2011-03-25 00:06:40 +08:00
|
|
|
{
|
|
|
|
int index_count = -1;
|
2014-07-30 12:28:15 +08:00
|
|
|
return layer2index(folder(), layer, &index_count);
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
|
|
|
|
2014-08-08 07:19:31 +08:00
|
|
|
void Sprite::getLayersList(std::vector<Layer*>& layers) const
|
|
|
|
{
|
|
|
|
// TODO support subfolders
|
|
|
|
LayerConstIterator it = m_folder->getLayerBegin();
|
|
|
|
LayerConstIterator end = m_folder->getLayerEnd();
|
|
|
|
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
layers.push_back(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Palettes
|
|
|
|
|
2014-12-28 22:06:11 +08:00
|
|
|
Palette* Sprite::palette(frame_t frame) const
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2010-08-04 10:33:44 +08:00
|
|
|
ASSERT(frame >= 0);
|
2010-03-31 08:43:18 +08:00
|
|
|
|
|
|
|
Palette* found = NULL;
|
|
|
|
|
2010-10-01 08:38:01 +08:00
|
|
|
PalettesList::const_iterator end = m_palettes.end();
|
|
|
|
PalettesList::const_iterator it = m_palettes.begin();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
Palette* pal = *it;
|
2014-07-30 12:28:15 +08:00
|
|
|
if (frame < pal->frame())
|
2010-03-31 08:43:18 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
found = pal;
|
2014-07-30 12:28:15 +08:00
|
|
|
if (frame == pal->frame())
|
2010-03-31 08:43:18 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-08-04 10:33:44 +08:00
|
|
|
ASSERT(found != NULL);
|
2010-03-31 08:43:18 +08:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2011-03-28 10:21:22 +08:00
|
|
|
const PalettesList& Sprite::getPalettes() const
|
2011-03-25 00:06:40 +08:00
|
|
|
{
|
|
|
|
return m_palettes;
|
|
|
|
}
|
|
|
|
|
2011-03-28 10:21:22 +08:00
|
|
|
void Sprite::setPalette(const Palette* pal, bool truncate)
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2010-08-04 10:33:44 +08:00
|
|
|
ASSERT(pal != NULL);
|
2010-03-31 08:43:18 +08:00
|
|
|
|
|
|
|
if (!truncate) {
|
2014-12-29 07:39:11 +08:00
|
|
|
Palette* sprite_pal = palette(pal->frame());
|
2010-03-31 08:43:18 +08:00
|
|
|
pal->copyColorsTo(sprite_pal);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Palette* other;
|
|
|
|
|
2010-10-01 08:38:01 +08:00
|
|
|
PalettesList::iterator end = m_palettes.end();
|
|
|
|
PalettesList::iterator it = m_palettes.begin();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
other = *it;
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2014-07-30 12:28:15 +08:00
|
|
|
if (pal->frame() == other->frame()) {
|
2012-01-06 06:45:03 +08:00
|
|
|
pal->copyColorsTo(other);
|
|
|
|
return;
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
2014-07-30 12:28:15 +08:00
|
|
|
else if (pal->frame() < other->frame())
|
2012-01-06 06:45:03 +08:00
|
|
|
break;
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-10-01 08:38:01 +08:00
|
|
|
m_palettes.insert(it, new Palette(*pal));
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
void Sprite::resetPalettes()
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2010-10-01 08:38:01 +08:00
|
|
|
PalettesList::iterator end = m_palettes.end();
|
|
|
|
PalettesList::iterator it = m_palettes.begin();
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2010-10-03 09:58:50 +08:00
|
|
|
if (it != end) {
|
2012-01-06 06:45:03 +08:00
|
|
|
++it; // Leave the first palette only.
|
2010-10-03 09:58:50 +08:00
|
|
|
while (it != end) {
|
2012-01-06 06:45:03 +08:00
|
|
|
delete *it; // palette
|
2010-10-03 09:58:50 +08:00
|
|
|
it = m_palettes.erase(it);
|
2011-01-19 06:22:03 +08:00
|
|
|
end = m_palettes.end();
|
2010-10-03 09:58:50 +08:00
|
|
|
}
|
|
|
|
}
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
|
|
|
|
2015-04-16 00:58:35 +08:00
|
|
|
void Sprite::deletePalette(frame_t frame)
|
2010-03-31 08:43:18 +08:00
|
|
|
{
|
2015-04-16 00:58:35 +08:00
|
|
|
auto it = m_palettes.begin(), end = m_palettes.end();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
Palette* pal = *it;
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2015-04-16 00:58:35 +08:00
|
|
|
if (pal->frame() == frame) {
|
|
|
|
delete pal; // delete palette
|
|
|
|
m_palettes.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
|
|
|
|
2015-03-20 05:47:57 +08:00
|
|
|
RgbMap* Sprite::rgbMap(frame_t frame) const
|
2010-04-21 10:44:31 +08:00
|
|
|
{
|
2014-07-30 12:28:15 +08:00
|
|
|
int mask_color = (backgroundLayer() ? -1: transparentColor());
|
2014-07-20 09:01:39 +08:00
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
if (m_rgbMap == NULL) {
|
|
|
|
m_rgbMap = new RgbMap();
|
2014-12-29 07:39:11 +08:00
|
|
|
m_rgbMap->regenerate(palette(frame), mask_color);
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
2014-12-29 07:39:11 +08:00
|
|
|
else if (!m_rgbMap->match(palette(frame))) {
|
|
|
|
m_rgbMap->regenerate(palette(frame), mask_color);
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
2014-07-20 09:01:39 +08:00
|
|
|
|
2011-03-25 00:06:40 +08:00
|
|
|
return m_rgbMap;
|
2010-04-21 10:44:31 +08:00
|
|
|
}
|
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Frames
|
2008-10-14 11:11:59 +08:00
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
void Sprite::addFrame(frame_t newFrame)
|
2013-03-12 07:29:45 +08:00
|
|
|
{
|
2014-12-29 07:39:11 +08:00
|
|
|
setTotalFrames(m_frames+1);
|
|
|
|
for (frame_t i=m_frames-1; i>=newFrame; --i)
|
|
|
|
setFrameDuration(i, frameDuration(i-1));
|
2015-01-19 09:05:33 +08:00
|
|
|
|
|
|
|
folder()->displaceFrames(newFrame, +1);
|
2013-03-12 07:29:45 +08:00
|
|
|
}
|
|
|
|
|
2015-01-19 09:05:33 +08:00
|
|
|
void Sprite::removeFrame(frame_t frame)
|
2013-03-12 07:29:45 +08:00
|
|
|
{
|
2015-01-19 09:05:33 +08:00
|
|
|
folder()->displaceFrames(frame, -1);
|
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
frame_t newTotal = m_frames-1;
|
2015-01-19 09:05:33 +08:00
|
|
|
for (frame_t i=frame; i<newTotal; ++i)
|
2014-12-29 07:39:11 +08:00
|
|
|
setFrameDuration(i, frameDuration(i+1));
|
2013-03-12 07:29:45 +08:00
|
|
|
setTotalFrames(newTotal);
|
|
|
|
}
|
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
void Sprite::setTotalFrames(frame_t frames)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2014-12-29 07:39:11 +08:00
|
|
|
frames = MAX(frame_t(1), frames);
|
2011-03-25 00:06:40 +08:00
|
|
|
m_frlens.resize(frames);
|
|
|
|
|
|
|
|
if (frames > m_frames) {
|
2014-12-29 07:39:11 +08:00
|
|
|
for (frame_t c=m_frames; c<frames; ++c)
|
|
|
|
m_frlens[c] = m_frlens[m_frames-1];
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
m_frames = frames;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
int Sprite::frameDuration(frame_t frame) const
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-25 00:06:40 +08:00
|
|
|
if (frame >= 0 && frame < m_frames)
|
|
|
|
return m_frlens[frame];
|
|
|
|
else
|
|
|
|
return 0;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
void Sprite::setFrameDuration(frame_t frame, int msecs)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-25 00:06:40 +08:00
|
|
|
if (frame >= 0 && frame < m_frames)
|
|
|
|
m_frlens[frame] = MID(1, msecs, 65535);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
void Sprite::setFrameRangeDuration(frame_t from, frame_t to, int msecs)
|
2013-12-23 03:30:04 +08:00
|
|
|
{
|
|
|
|
std::fill(
|
2015-03-05 08:35:11 +08:00
|
|
|
m_frlens.begin()+(std::size_t)from,
|
|
|
|
m_frlens.begin()+(std::size_t)to+1, MID(1, msecs, 65535));
|
2013-12-23 03:30:04 +08:00
|
|
|
}
|
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
void Sprite::setDurationForAllFrames(int msecs)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-25 00:06:40 +08:00
|
|
|
std::fill(m_frlens.begin(), m_frlens.end(), MID(1, msecs, 65535));
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2015-02-09 22:40:43 +08:00
|
|
|
// Shared Images and CelData (for linked Cels)
|
2010-03-31 08:43:18 +08:00
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
ImageRef Sprite::getImageRef(ObjectId imageId)
|
2015-01-04 21:58:14 +08:00
|
|
|
{
|
2015-02-09 22:40:43 +08:00
|
|
|
for (Cel* cel : cels()) {
|
2015-01-04 21:58:14 +08:00
|
|
|
if (cel->image()->id() == imageId)
|
|
|
|
return cel->imageRef();
|
|
|
|
}
|
2015-02-09 22:40:43 +08:00
|
|
|
return ImageRef(nullptr);
|
2015-01-04 21:58:14 +08:00
|
|
|
}
|
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
CelDataRef Sprite::getCelDataRef(ObjectId celDataId)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2015-02-09 22:40:43 +08:00
|
|
|
for (Cel* cel : cels()) {
|
|
|
|
if (cel->dataRef()->id() == celDataId)
|
|
|
|
return cel->dataRef();
|
2015-01-04 21:58:14 +08:00
|
|
|
}
|
2015-02-09 22:40:43 +08:00
|
|
|
return CelDataRef(nullptr);
|
2010-03-31 08:43:18 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Images
|
2008-03-27 22:29:33 +08:00
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
void Sprite::replaceImage(ObjectId curImageId, const ImageRef& newImage)
|
2015-01-19 09:05:33 +08:00
|
|
|
{
|
2015-02-09 22:40:43 +08:00
|
|
|
for (Cel* cel : cels()) {
|
|
|
|
if (cel->image()->id() == curImageId)
|
|
|
|
cel->data()->setImage(newImage);
|
2015-01-19 09:05:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 21:58:14 +08:00
|
|
|
// TODO replace it with a images iterator
|
|
|
|
void Sprite::getImages(std::vector<Image*>& images) const
|
2014-05-02 22:28:03 +08:00
|
|
|
{
|
2015-02-09 22:40:43 +08:00
|
|
|
for (const auto& cel : uniqueCels())
|
|
|
|
images.push_back(cel->image());
|
2014-05-02 22:28:03 +08:00
|
|
|
}
|
|
|
|
|
2015-03-23 23:57:59 +08:00
|
|
|
void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const Remap& remap)
|
2010-06-17 13:13:42 +08:00
|
|
|
{
|
2012-02-13 10:21:06 +08:00
|
|
|
ASSERT(m_format == IMAGE_INDEXED);
|
2015-03-23 23:57:59 +08:00
|
|
|
ASSERT(remap.size() == 256);
|
2011-03-25 00:06:40 +08:00
|
|
|
|
2015-03-23 23:57:59 +08:00
|
|
|
for (const Cel* cel : uniqueCels()) {
|
2011-03-25 00:06:40 +08:00
|
|
|
// Remap this Cel because is inside the specified range
|
2014-07-30 12:28:15 +08:00
|
|
|
if (cel->frame() >= frameFrom &&
|
|
|
|
cel->frame() <= frameTo) {
|
|
|
|
Image* image = cel->image();
|
2013-11-10 06:59:05 +08:00
|
|
|
LockImageBits<IndexedTraits> bits(image);
|
|
|
|
LockImageBits<IndexedTraits>::iterator
|
|
|
|
it = bits.begin(),
|
|
|
|
end = bits.end();
|
2011-03-25 00:06:40 +08:00
|
|
|
|
2013-11-10 06:59:05 +08:00
|
|
|
for (; it != end; ++it)
|
2015-03-23 23:57:59 +08:00
|
|
|
*it = remap[*it];
|
2011-03-25 00:06:40 +08:00
|
|
|
}
|
|
|
|
}
|
2010-06-17 13:13:42 +08:00
|
|
|
}
|
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Drawing
|
|
|
|
|
2014-12-29 07:39:11 +08:00
|
|
|
void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const
|
2014-11-17 05:33:31 +08:00
|
|
|
{
|
|
|
|
std::vector<Layer*> layers;
|
|
|
|
getLayersList(layers);
|
|
|
|
|
|
|
|
for (int i=(int)layers.size()-1; i>=0; --i) {
|
|
|
|
Layer* layer = layers[i];
|
2014-12-03 22:15:09 +08:00
|
|
|
if (!layer->isImage() || !layer->isVisible())
|
2014-11-17 05:33:31 +08:00
|
|
|
continue;
|
|
|
|
|
2014-12-29 08:04:08 +08:00
|
|
|
Cel* cel = layer->cel(frame);
|
2014-11-17 05:33:31 +08:00
|
|
|
if (!cel)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Image* image = cel->image();
|
|
|
|
if (!image)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!cel->bounds().contains(gfx::Point(x, y)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
color_t color = get_pixel(image,
|
|
|
|
x - cel->x(),
|
|
|
|
y - cel->y());
|
|
|
|
|
|
|
|
bool isOpaque = true;
|
|
|
|
|
|
|
|
switch (image->pixelFormat()) {
|
|
|
|
case IMAGE_RGB:
|
|
|
|
isOpaque = (rgba_geta(color) >= opacityThreshold);
|
|
|
|
break;
|
|
|
|
case IMAGE_INDEXED:
|
|
|
|
isOpaque = (color != image->maskColor());
|
|
|
|
break;
|
|
|
|
case IMAGE_GRAYSCALE:
|
|
|
|
isOpaque = (graya_geta(color) >= opacityThreshold);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isOpaque)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cels.push_back(cel);
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
2015-02-09 22:40:43 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2010-03-31 08:43:18 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2008-03-27 22:29:33 +08:00
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
static Layer* index2layer(const Layer* layer, const LayerIndex& index, int* index_count)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2008-02-04 10:37:26 +08:00
|
|
|
if (index == *index_count)
|
2009-06-11 08:59:57 +08:00
|
|
|
return (Layer*)layer;
|
2007-09-19 07:57:02 +08:00
|
|
|
else {
|
2008-02-04 10:37:26 +08:00
|
|
|
(*index_count)++;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
if (layer->isFolder()) {
|
2007-09-19 07:57:02 +08:00
|
|
|
Layer *found;
|
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin();
|
|
|
|
LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
|
2009-11-17 21:12:26 +08:00
|
|
|
|
|
|
|
for (; it != end; ++it) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if ((found = index2layer(*it, index, index_count)))
|
|
|
|
return found;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
static LayerIndex layer2index(const Layer* layer, const Layer* find_layer, int* index_count)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
if (layer == find_layer)
|
2012-08-24 08:32:55 +08:00
|
|
|
return LayerIndex(*index_count);
|
2007-09-19 07:57:02 +08:00
|
|
|
else {
|
2008-02-04 10:37:26 +08:00
|
|
|
(*index_count)++;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
if (layer->isFolder()) {
|
2007-09-19 07:57:02 +08:00
|
|
|
int found;
|
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin();
|
|
|
|
LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd();
|
2009-11-17 21:12:26 +08:00
|
|
|
|
|
|
|
for (; it != end; ++it) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if ((found = layer2index(*it, find_layer, index_count)) >= 0)
|
2012-08-24 08:32:55 +08:00
|
|
|
return LayerIndex(found);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-24 08:32:55 +08:00
|
|
|
return LayerIndex(-1);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
} // namespace doc
|