aseprite/src/doc/sprite.cpp

604 lines
13 KiB
C++
Raw Normal View History

// Aseprite Document Library
// Copyright (c) 2001-2016 David Capello
//
// 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
#ifdef HAVE_CONFIG_H
2007-09-19 07:57:02 +08:00
#include "config.h"
#endif
2007-09-19 07:57:02 +08:00
#include "doc/sprite.h"
#include "base/base.h"
#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"
#include "doc/cel.h"
#include "doc/cels_range.h"
#include "doc/frame_tag.h"
#include "doc/image_impl.h"
#include "doc/layer.h"
#include "doc/layers_range.h"
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/remap.h"
#include "doc/rgbmap.h"
2007-09-19 07:57:02 +08:00
#include <cstring>
#include <vector>
namespace doc {
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
//////////////////////////////////////////////////////////////////////
// Constructors/Destructor
Sprite::Sprite(PixelFormat format, int width, int height, int ncolors)
: Object(ObjectType::Sprite)
, m_document(NULL)
2016-05-14 04:08:07 +08:00
, m_spec((ColorMode)format, width, height, 0)
2016-05-24 04:30:34 +08:00
, m_pixelRatio(1, 1)
2012-07-09 08:09:09 +08:00
, m_frames(1)
2015-02-17 22:37:42 +08:00
, m_frameTags(this)
{
ASSERT(width > 0 && height > 0);
m_frlens.push_back(100); // First frame with 100 msecs of duration
2016-06-08 06:38:56 +08:00
m_root = new LayerGroup(this);
2007-09-19 07:57:02 +08:00
// Generate palette
switch (format) {
case IMAGE_GRAYSCALE: ncolors = 256; break;
case IMAGE_BITMAP: ncolors = 2; break;
}
Palette pal(frame_t(0), ncolors);
switch (format) {
2007-09-19 07:57:02 +08:00
// For black and white images
2007-09-19 07:57:02 +08:00
case IMAGE_GRAYSCALE:
case IMAGE_BITMAP:
for (int c=0; c<ncolors; c++) {
int g = 255 * c / (ncolors-1);
g = MID(0, g, 255);
pal.setEntry(c, rgba(g, g, g, 255));
}
2007-09-19 07:57:02 +08:00
break;
}
// Initial RGB map
m_rgbMap = NULL;
setPalette(&pal, true);
2007-09-19 07:57:02 +08:00
}
2016-05-14 04:08:07 +08:00
Sprite::Sprite(const ImageSpec& spec, int ncolors)
: Sprite((PixelFormat)spec.colorMode(), spec.width(), spec.height(), ncolors)
{
}
Sprite::~Sprite()
2007-09-19 07:57:02 +08:00
{
// Destroy layers
2016-06-08 06:38:56 +08:00
delete m_root;
// 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)
delete *it; // palette
}
// Destroy RGB map
delete m_rgbMap;
}
// static
Sprite* Sprite::createBasicSprite(doc::PixelFormat format, int width, int height, int ncolors)
{
// Create the sprite.
base::UniquePtr<doc::Sprite> sprite(new doc::Sprite(format, width, height, ncolors));
sprite->setTotalFrames(doc::frame_t(1));
// Create the main image.
doc::ImageRef image(doc::Image::create(format, width, height));
doc::clear_image(image.get(), 0);
// Create the first transparent layer.
{
base::UniquePtr<doc::LayerImage> layer(new doc::LayerImage(sprite));
layer->setName("Layer 1");
// Create the cel.
{
base::UniquePtr<doc::Cel> cel(new doc::Cel(doc::frame_t(0), image));
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.
2016-06-08 06:38:56 +08:00
sprite->root()->addLayer(layer.release()); // Release the layer because it's owned by the sprite
}
return sprite.release();
}
//////////////////////////////////////////////////////////////////////
// Main properties
void Sprite::setPixelFormat(PixelFormat format)
{
2016-05-14 04:08:07 +08:00
m_spec.setColorMode((ColorMode)format);
}
2016-05-24 04:30:34 +08:00
void Sprite::setPixelRatio(const PixelRatio& pixelRatio)
{
m_pixelRatio = pixelRatio;
}
void Sprite::setSize(int width, int height)
{
ASSERT(width > 0);
ASSERT(height > 0);
2016-05-14 04:08:07 +08:00
m_spec.setSize(width, height);
}
bool Sprite::needAlpha() const
{
2016-05-14 04:08:07 +08:00
switch (pixelFormat()) {
case IMAGE_RGB:
case IMAGE_GRAYSCALE: {
Layer* bg = backgroundLayer();
return (!bg || !bg->isVisible());
}
}
return false;
}
bool Sprite::supportAlpha() const
{
2016-05-14 04:08:07 +08:00
switch (pixelFormat()) {
case IMAGE_RGB:
case IMAGE_GRAYSCALE:
return true;
}
return false;
}
void Sprite::setTransparentColor(color_t color)
{
2016-05-14 04:08:07 +08:00
m_spec.setMaskColor(color);
// Change the mask color of all images.
std::vector<Image*> images;
getImages(images);
for (Image* image : images)
image->setMaskColor(color);
}
int Sprite::getMemSize() const
{
int size = 0;
std::vector<Image*> images;
getImages(images);
for (Image* image : images)
size += image->getRowStrideSize() * image->height();
2007-09-19 07:57:02 +08:00
return size;
}
//////////////////////////////////////////////////////////////////////
// Layers
LayerImage* Sprite::backgroundLayer() const
{
2016-06-08 06:38:56 +08:00
if (root()->layersCount() > 0) {
Layer* bglayer = root()->layers().front();
if (bglayer->isBackground()) {
ASSERT(bglayer->isImage());
return static_cast<LayerImage*>(bglayer);
}
}
return NULL;
2007-09-19 07:57:02 +08:00
}
LayerIndex Sprite::countLayers() const
{
2016-06-08 06:38:56 +08:00
return LayerIndex(root()->layersCount());
}
LayerIndex Sprite::firstLayer() const
{
return LayerIndex(0);
}
LayerIndex Sprite::lastLayer() const
{
2016-06-08 06:38:56 +08:00
return LayerIndex(root()->layersCount()-1);
}
Layer* Sprite::layer(int layerIndex) const
{
return indexToLayer(LayerIndex(layerIndex));
}
Layer* Sprite::indexToLayer(LayerIndex index) const
{
if (index < LayerIndex(0))
return NULL;
int index_count = -1;
2016-06-08 06:38:56 +08:00
return index2layer(root(), index, &index_count);
}
LayerIndex Sprite::layerToIndex(const Layer* layer) const
{
int index_count = -1;
2016-06-08 06:38:56 +08:00
return layer2index(root(), layer, &index_count);
}
void Sprite::getLayersList(std::vector<Layer*>& layers) const
{
2016-06-08 06:38:56 +08:00
// TODO support subgroups
for (Layer* child : m_root->layers()) {
layers.push_back(child);
}
}
//////////////////////////////////////////////////////////////////////
// Palettes
Palette* Sprite::palette(frame_t frame) const
{
ASSERT(frame >= 0);
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;
if (frame < pal->frame())
break;
found = pal;
if (frame == pal->frame())
break;
}
ASSERT(found != NULL);
return found;
}
const PalettesList& Sprite::getPalettes() const
{
return m_palettes;
}
void Sprite::setPalette(const Palette* pal, bool truncate)
{
ASSERT(pal != NULL);
if (!truncate) {
Palette* sprite_pal = palette(pal->frame());
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;
if (pal->frame() == other->frame()) {
pal->copyColorsTo(other);
return;
}
else if (pal->frame() < other->frame())
break;
}
2007-09-19 07:57:02 +08:00
2010-10-01 08:38:01 +08:00
m_palettes.insert(it, new Palette(*pal));
}
}
void Sprite::resetPalettes()
{
2010-10-01 08:38:01 +08:00
PalettesList::iterator end = m_palettes.end();
PalettesList::iterator it = m_palettes.begin();
if (it != end) {
++it; // Leave the first palette only.
while (it != end) {
delete *it; // palette
it = m_palettes.erase(it);
end = m_palettes.end();
}
}
}
void Sprite::deletePalette(frame_t frame)
{
auto it = m_palettes.begin(), end = m_palettes.end();
for (; it != end; ++it) {
Palette* pal = *it;
if (pal->frame() == frame) {
delete pal; // delete palette
m_palettes.erase(it);
break;
}
}
}
RgbMap* Sprite::rgbMap(frame_t frame) const
{
return rgbMap(frame, backgroundLayer() ? RgbMapFor::OpaqueLayer:
RgbMapFor::TransparentLayer);
}
RgbMap* Sprite::rgbMap(frame_t frame, RgbMapFor forLayer) const
{
int maskIndex = (forLayer == RgbMapFor::OpaqueLayer ?
-1: transparentColor());
if (m_rgbMap == NULL) {
m_rgbMap = new RgbMap();
m_rgbMap->regenerate(palette(frame), maskIndex);
}
else if (!m_rgbMap->match(palette(frame)) ||
m_rgbMap->maskIndex() != maskIndex) {
m_rgbMap->regenerate(palette(frame), maskIndex);
}
return m_rgbMap;
}
//////////////////////////////////////////////////////////////////////
// Frames
void Sprite::addFrame(frame_t newFrame)
{
setTotalFrames(m_frames+1);
for (frame_t i=m_frames-1; i>=newFrame; --i)
setFrameDuration(i, frameDuration(i-1));
2016-06-08 06:38:56 +08:00
root()->displaceFrames(newFrame, +1);
}
void Sprite::removeFrame(frame_t frame)
{
2016-06-08 06:38:56 +08:00
root()->displaceFrames(frame, -1);
frame_t newTotal = m_frames-1;
for (frame_t i=frame; i<newTotal; ++i)
setFrameDuration(i, frameDuration(i+1));
setTotalFrames(newTotal);
}
void Sprite::setTotalFrames(frame_t frames)
2007-09-19 07:57:02 +08:00
{
frames = MAX(frame_t(1), frames);
m_frlens.resize(frames);
if (frames > m_frames) {
for (frame_t c=m_frames; c<frames; ++c)
m_frlens[c] = m_frlens[m_frames-1];
}
m_frames = frames;
2007-09-19 07:57:02 +08:00
}
int Sprite::frameDuration(frame_t frame) const
2007-09-19 07:57:02 +08:00
{
if (frame >= 0 && frame < m_frames)
return m_frlens[frame];
else
return 0;
2007-09-19 07:57:02 +08:00
}
void Sprite::setFrameDuration(frame_t frame, int msecs)
2007-09-19 07:57:02 +08:00
{
if (frame >= 0 && frame < m_frames)
m_frlens[frame] = MID(1, msecs, 65535);
2007-09-19 07:57:02 +08:00
}
void Sprite::setFrameRangeDuration(frame_t from, frame_t to, int msecs)
{
std::fill(
m_frlens.begin()+(std::size_t)from,
m_frlens.begin()+(std::size_t)to+1, MID(1, msecs, 65535));
}
void Sprite::setDurationForAllFrames(int msecs)
2007-09-19 07:57:02 +08:00
{
std::fill(m_frlens.begin(), m_frlens.end(), MID(1, msecs, 65535));
}
2007-09-19 07:57:02 +08:00
//////////////////////////////////////////////////////////////////////
// Shared Images and CelData (for linked Cels)
ImageRef Sprite::getImageRef(ObjectId imageId)
{
for (Cel* cel : cels()) {
if (cel->image()->id() == imageId)
return cel->imageRef();
}
return ImageRef(nullptr);
}
CelDataRef Sprite::getCelDataRef(ObjectId celDataId)
2007-09-19 07:57:02 +08:00
{
for (Cel* cel : cels()) {
if (cel->dataRef()->id() == celDataId)
return cel->dataRef();
}
return CelDataRef(nullptr);
}
2007-09-19 07:57:02 +08:00
//////////////////////////////////////////////////////////////////////
// Images
void Sprite::replaceImage(ObjectId curImageId, const ImageRef& newImage)
{
for (Cel* cel : cels()) {
if (cel->image()->id() == curImageId)
cel->data()->setImage(newImage);
}
}
// TODO replace it with a images iterator
void Sprite::getImages(std::vector<Image*>& images) const
{
for (const auto& cel : uniqueCels())
images.push_back(cel->image());
}
void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const Remap& remap)
2010-06-17 13:13:42 +08:00
{
2016-05-14 04:08:07 +08:00
ASSERT(pixelFormat() == IMAGE_INDEXED);
//ASSERT(remap.size() == 256);
for (const Cel* cel : uniqueCels()) {
// Remap this Cel because is inside the specified range
if (cel->frame() >= frameFrom &&
cel->frame() <= frameTo) {
remap_image(cel->image(), remap);
}
}
2010-06-17 13:13:42 +08:00
}
//////////////////////////////////////////////////////////////////////
// Drawing
void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const
{
std::vector<Layer*> layers;
getLayersList(layers);
for (int i=(int)layers.size()-1; i>=0; --i) {
Layer* layer = layers[i];
if (!layer->isImage() || !layer->isVisible())
continue;
Cel* cel = layer->cel(frame);
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);
}
//////////////////////////////////////////////////////////////////////
// Iterators
LayersRange Sprite::layers() const
{
return LayersRange(this, LayerIndex(0), LayerIndex(countLayers()-1));
}
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);
}
CelsRange Sprite::uniqueCels(frame_t from, frame_t to) const
{
return CelsRange(this, from, to, CelsRange::UNIQUE);
}
//////////////////////////////////////////////////////////////////////
static Layer* index2layer(const Layer* layer, const LayerIndex& index, int* index_count)
2007-09-19 07:57:02 +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 {
(*index_count)++;
2007-09-19 07:57:02 +08:00
2016-06-08 06:38:56 +08:00
if (layer->isGroup()) {
2007-09-19 07:57:02 +08:00
Layer *found;
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers()) {
if ((found = index2layer(child, index, index_count)))
return found;
2007-09-19 07:57:02 +08:00
}
}
return NULL;
}
}
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)
return LayerIndex(*index_count);
2007-09-19 07:57:02 +08:00
else {
(*index_count)++;
2007-09-19 07:57:02 +08:00
2016-06-08 06:38:56 +08:00
if (layer->isGroup()) {
2007-09-19 07:57:02 +08:00
int found;
for (const Layer* child : static_cast<const LayerGroup*>(layer)->layers()) {
if ((found = layer2index(child, find_layer, index_count)) >= 0)
return LayerIndex(found);
2007-09-19 07:57:02 +08:00
}
}
return LayerIndex(-1);
2007-09-19 07:57:02 +08:00
}
}
} // namespace doc