1// Aseprite Document Library
2// Copyright (C) 2018-2022 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "doc/sprite.h"
13
14#include "base/memory.h"
15#include "base/remove_from_container.h"
16#include "doc/cel.h"
17#include "doc/cels_range.h"
18#include "doc/image_impl.h"
19#include "doc/layer.h"
20#include "doc/layer_tilemap.h"
21#include "doc/octree_map.h"
22#include "doc/palette.h"
23#include "doc/primitives.h"
24#include "doc/remap.h"
25#include "doc/rgbmap_rgb5a3.h"
26#include "doc/tag.h"
27#include "doc/tilesets.h"
28
29#include <algorithm>
30#include <cstring>
31#include <memory>
32#include <vector>
33
34namespace doc {
35
36static RgbMapAlgorithm g_rgbMapAlgorithm = RgbMapAlgorithm::DEFAULT;
37static gfx::Rect g_defaultGridBounds(0, 0, 16, 16);
38
39// static
40gfx::Rect Sprite::DefaultGridBounds()
41{
42 return g_defaultGridBounds;
43}
44
45// static
46void Sprite::SetDefaultGridBounds(const gfx::Rect& defGridBounds)
47{
48 g_defaultGridBounds = defGridBounds;
49}
50
51// static
52RgbMapAlgorithm Sprite::DefaultRgbMapAlgorithm()
53{
54 return g_rgbMapAlgorithm;
55}
56
57// static
58void Sprite::SetDefaultRgbMapAlgorithm(const RgbMapAlgorithm mapAlgo)
59{
60 g_rgbMapAlgorithm = mapAlgo;
61}
62
63//////////////////////////////////////////////////////////////////////
64// Constructors/Destructor
65
66Sprite::Sprite(const ImageSpec& spec,
67 int ncolors)
68 : WithUserData(ObjectType::Sprite)
69 , m_document(nullptr)
70 , m_spec(spec)
71 , m_pixelRatio(1, 1)
72 , m_frames(1)
73 , m_frlens(1, 100) // First frame with 100 msecs of duration
74 , m_root(new LayerGroup(this))
75 , m_gridBounds(Sprite::DefaultGridBounds())
76 , m_tags(this)
77 , m_slices(this)
78 , m_tilesets(nullptr)
79{
80 // Generate palette
81 switch (spec.colorMode()) {
82 case ColorMode::GRAYSCALE: ncolors = 256; break;
83 case ColorMode::BITMAP: ncolors = 2; break;
84 }
85
86 Palette pal(frame_t(0), ncolors);
87
88 switch (spec.colorMode()) {
89
90 // For black and white images
91 case ColorMode::GRAYSCALE:
92 case ColorMode::BITMAP:
93 for (int c=0; c<ncolors; c++) {
94 int g = 255 * c / (ncolors-1);
95 g = std::clamp(g, 0, 255);
96 pal.setEntry(c, rgba(g, g, g, 255));
97 }
98 break;
99 }
100
101 setPalette(&pal, true);
102}
103
104Sprite::~Sprite()
105{
106 // Destroy layers
107 delete m_root;
108
109 // Destroy tilesets
110 delete m_tilesets;
111
112 // Destroy palettes
113 {
114 PalettesList::iterator end = m_palettes.end();
115 PalettesList::iterator it = m_palettes.begin();
116 for (; it != end; ++it)
117 delete *it; // palette
118 }
119}
120
121// static
122Sprite* Sprite::MakeStdSprite(const ImageSpec& spec,
123 const int ncolors,
124 const ImageBufferPtr& imageBuf)
125{
126 // Create the sprite.
127 std::unique_ptr<Sprite> sprite(new Sprite(spec, ncolors));
128 sprite->setTotalFrames(frame_t(1));
129
130 // Create the main image.
131 ImageRef image(Image::create(spec, imageBuf));
132 clear_image(image.get(), 0);
133
134 // Create the first transparent layer.
135 {
136 std::unique_ptr<LayerImage> layer(new LayerImage(sprite.get()));
137 layer->setName("Layer 1");
138
139 // Create the cel.
140 {
141 std::unique_ptr<Cel> cel(new Cel(frame_t(0), image));
142 cel->setPosition(0, 0);
143
144 // Add the cel in the layer.
145 layer->addCel(cel.get());
146 cel.release(); // Release the cel because it is in the layer
147 }
148
149 // Add the layer in the sprite.
150 sprite->root()->addLayer(layer.release()); // Release the layer because it's owned by the sprite
151 }
152
153 return sprite.release();
154}
155
156//////////////////////////////////////////////////////////////////////
157// Main properties
158
159void Sprite::setPixelFormat(PixelFormat format)
160{
161 m_spec.setColorMode((ColorMode)format);
162}
163
164void Sprite::setPixelRatio(const PixelRatio& pixelRatio)
165{
166 m_pixelRatio = pixelRatio;
167}
168
169void Sprite::setSize(int width, int height)
170{
171 ASSERT(width > 0);
172 ASSERT(height > 0);
173
174 m_spec.setSize(width, height);
175}
176
177void Sprite::setColorSpace(const gfx::ColorSpaceRef& colorSpace)
178{
179 m_spec.setColorSpace(colorSpace);
180 for (auto cel : uniqueCels())
181 cel->image()->setColorSpace(colorSpace);
182}
183
184bool Sprite::isOpaque() const
185{
186 Layer* bg = backgroundLayer();
187 return (bg && bg->isVisible());
188}
189
190bool Sprite::needAlpha() const
191{
192 switch (pixelFormat()) {
193 case IMAGE_RGB:
194 case IMAGE_GRAYSCALE:
195 return !isOpaque();
196 default:
197 return false;
198 }
199}
200
201bool Sprite::supportAlpha() const
202{
203 switch (pixelFormat()) {
204 case IMAGE_RGB:
205 case IMAGE_GRAYSCALE:
206 return true;
207 }
208 return false;
209}
210
211void Sprite::setTransparentColor(color_t color)
212{
213#if _DEBUG
214 if (colorMode() != ColorMode::INDEXED) {
215 ASSERT(color == 0);
216 }
217#endif // _DEBUG
218
219 m_spec.setMaskColor(color);
220
221 // Change the mask color of all images.
222 std::vector<ImageRef> images;
223 getImages(images);
224 for (ImageRef& image : images)
225 image->setMaskColor(color);
226
227 // Transform the empty tile of all tilemaps
228 if (hasTilesets()) {
229 for (Tileset* tileset : *tilesets())
230 tileset->notifyRegenerateEmptyTile();
231 }
232}
233
234int Sprite::getMemSize() const
235{
236 int size = 0;
237
238 std::vector<ImageRef> images;
239 getImages(images);
240 for (const ImageRef& image : images)
241 size += image->getRowStrideSize() * image->height();
242
243 return size;
244}
245
246//////////////////////////////////////////////////////////////////////
247// Layers
248
249LayerImage* Sprite::backgroundLayer() const
250{
251 if (root()->layersCount() > 0) {
252 Layer* bglayer = root()->layers().front();
253
254 if (bglayer->isBackground()) {
255 ASSERT(bglayer->isImage());
256 return static_cast<LayerImage*>(bglayer);
257 }
258 }
259 return NULL;
260}
261
262Layer* Sprite::firstLayer() const
263{
264 Layer* layer = root()->firstLayer();
265 while (layer->isGroup())
266 layer = static_cast<LayerGroup*>(layer)->firstLayer();
267 return layer;
268}
269
270Layer* Sprite::firstBrowsableLayer() const
271{
272 Layer* layer = root()->firstLayer();
273 while (layer->isBrowsable())
274 layer = static_cast<LayerGroup*>(layer)->firstLayer();
275 return layer;
276}
277
278layer_t Sprite::allLayersCount() const
279{
280 return root()->allLayersCount();
281}
282
283bool Sprite::hasVisibleReferenceLayers() const
284{
285 return root()->hasVisibleReferenceLayers();
286}
287
288//////////////////////////////////////////////////////////////////////
289// Palettes
290
291Palette* Sprite::palette(frame_t frame) const
292{
293 ASSERT(frame >= 0);
294
295 Palette* found = NULL;
296
297 PalettesList::const_iterator end = m_palettes.end();
298 PalettesList::const_iterator it = m_palettes.begin();
299 for (; it != end; ++it) {
300 Palette* pal = *it;
301 if (frame < pal->frame())
302 break;
303
304 found = pal;
305 if (frame == pal->frame())
306 break;
307 }
308
309 ASSERT(found != NULL);
310 return found;
311}
312
313const PalettesList& Sprite::getPalettes() const
314{
315 return m_palettes;
316}
317
318void Sprite::setPalette(const Palette* pal, bool truncate)
319{
320 ASSERT(pal != NULL);
321
322 if (!truncate) {
323 Palette* sprite_pal = palette(pal->frame());
324 pal->copyColorsTo(sprite_pal);
325 }
326 else {
327 Palette* other;
328
329 PalettesList::iterator end = m_palettes.end();
330 PalettesList::iterator it = m_palettes.begin();
331 for (; it != end; ++it) {
332 other = *it;
333
334 if (pal->frame() == other->frame()) {
335 pal->copyColorsTo(other);
336 return;
337 }
338 else if (pal->frame() < other->frame())
339 break;
340 }
341
342 m_palettes.insert(it, new Palette(*pal));
343 }
344}
345
346void Sprite::resetPalettes()
347{
348 PalettesList::iterator end = m_palettes.end();
349 PalettesList::iterator it = m_palettes.begin();
350
351 if (it != end) {
352 ++it; // Leave the first palette only.
353 while (it != end) {
354 delete *it; // palette
355 it = m_palettes.erase(it);
356 end = m_palettes.end();
357 }
358 }
359}
360
361void Sprite::deletePalette(frame_t frame)
362{
363 auto it = m_palettes.begin(), end = m_palettes.end();
364 for (; it != end; ++it) {
365 Palette* pal = *it;
366
367 if (pal->frame() == frame) {
368 delete pal; // delete palette
369 m_palettes.erase(it);
370 break;
371 }
372 }
373}
374
375Sprite::RgbMapFor Sprite::rgbMapForSprite() const
376{
377 return backgroundLayer() ? RgbMapFor::OpaqueLayer:
378 RgbMapFor::TransparentLayer;
379}
380
381RgbMap* Sprite::rgbMap(const frame_t frame) const
382{
383 return rgbMap(frame, rgbMapForSprite());
384}
385
386RgbMap* Sprite::rgbMap(const frame_t frame,
387 const RgbMapFor forLayer) const
388{
389 return rgbMap(frame,
390 forLayer,
391 g_rgbMapAlgorithm);
392}
393
394RgbMap* Sprite::rgbMap(const frame_t frame,
395 const RgbMapFor forLayer,
396 RgbMapAlgorithm mapAlgo) const
397{
398 if (!m_rgbMap || m_rgbMapAlgorithm != mapAlgo) {
399 m_rgbMapAlgorithm = mapAlgo;
400 switch (m_rgbMapAlgorithm) {
401 case RgbMapAlgorithm::RGB5A3: m_rgbMap.reset(new RgbMapRGB5A3); break;
402 case RgbMapAlgorithm::DEFAULT:
403 case RgbMapAlgorithm::OCTREE: m_rgbMap.reset(new OctreeMap); break;
404 default:
405 m_rgbMap.reset(nullptr);
406 ASSERT(false);
407 return nullptr;
408 }
409 }
410 int maskIndex;
411 if (forLayer == RgbMapFor::OpaqueLayer)
412 maskIndex = -1;
413 else {
414 maskIndex = palette(frame)->findMaskColor();
415 if (maskIndex == -1)
416 maskIndex = 0;
417 }
418 m_rgbMap->regenerateMap(palette(frame), maskIndex);
419 return m_rgbMap.get();
420}
421
422//////////////////////////////////////////////////////////////////////
423// Frames
424
425void Sprite::addFrame(frame_t newFrame)
426{
427 setTotalFrames(m_frames+1);
428
429 frame_t to = std::max(1, newFrame);
430 for (frame_t i=m_frames-1; i>=to; --i)
431 setFrameDuration(i, frameDuration(i-1));
432
433 root()->displaceFrames(newFrame, +1);
434}
435
436void Sprite::removeFrame(frame_t frame)
437{
438 root()->displaceFrames(frame, -1);
439
440 frame_t newTotal = m_frames-1;
441 for (frame_t i=frame; i<newTotal; ++i)
442 setFrameDuration(i, frameDuration(i+1));
443 setTotalFrames(newTotal);
444}
445
446void Sprite::setTotalFrames(frame_t frames)
447{
448 frames = std::max(frame_t(1), frames);
449 m_frlens.resize(frames);
450
451 if (frames > m_frames) {
452 for (frame_t c=m_frames; c<frames; ++c)
453 m_frlens[c] = m_frlens[m_frames-1];
454 }
455
456 m_frames = frames;
457}
458
459int Sprite::frameDuration(frame_t frame) const
460{
461 if (frame >= 0 && frame < m_frames)
462 return m_frlens[frame];
463 else
464 return 0;
465}
466
467int Sprite::totalAnimationDuration() const
468{
469 int duration = 0;
470 for (frame_t frame=0; frame<m_frames; ++frame)
471 duration += frameDuration(frame);
472 return duration; // TODO cache this value
473}
474
475void Sprite::setFrameDuration(frame_t frame, int msecs)
476{
477 if (frame >= 0 && frame < m_frames)
478 m_frlens[frame] = std::clamp(msecs, 1, 65535);
479}
480
481void Sprite::setFrameRangeDuration(frame_t from, frame_t to, int msecs)
482{
483 std::fill(
484 m_frlens.begin()+(std::size_t)from,
485 m_frlens.begin()+(std::size_t)to+1, std::clamp(msecs, 1, 65535));
486}
487
488void Sprite::setDurationForAllFrames(int msecs)
489{
490 std::fill(m_frlens.begin(), m_frlens.end(), std::clamp(msecs, 1, 65535));
491}
492
493//////////////////////////////////////////////////////////////////////
494// Shared Images and CelData (for linked cels and tilesets)
495
496ImageRef Sprite::getImageRef(ObjectId imageId)
497{
498 for (Cel* cel : cels()) {
499 if (cel->image()->id() == imageId)
500 return cel->imageRef();
501 }
502 if (hasTilesets()) {
503 for (Tileset* tileset : *tilesets()) {
504 for (tile_index i=0; i<tileset->size(); ++i) {
505 ImageRef image = tileset->get(i);
506 if (image && image->id() == imageId)
507 return image;
508 }
509 }
510 }
511 return ImageRef(nullptr);
512}
513
514CelDataRef Sprite::getCelDataRef(ObjectId celDataId)
515{
516 for (Cel* cel : cels()) {
517 if (cel->dataRef()->id() == celDataId)
518 return cel->dataRef();
519 }
520 return CelDataRef(nullptr);
521}
522
523//////////////////////////////////////////////////////////////////////
524// Images
525
526void Sprite::replaceImage(ObjectId curImageId, const ImageRef& newImage)
527{
528 for (Cel* cel : cels()) {
529 if (cel->image()->id() == curImageId)
530 cel->data()->setImage(newImage, cel->layer());
531 }
532
533 if (hasTilesets()) {
534 for (Tileset* tileset : *tilesets()) {
535 for (tile_index i=0; i<tileset->size(); ++i) {
536 ImageRef image = tileset->get(i);
537 if (image && image->id() == curImageId)
538 tileset->set(i, newImage);
539 }
540 }
541 }
542}
543
544void Sprite::replaceTileset(tileset_index tsi, Tileset* newTileset)
545{
546 ASSERT(hasTilesets());
547
548 tilesets()->set(tsi, newTileset);
549
550 for (Layer* layer : allLayers()) {
551 if (layer->isTilemap() &&
552 static_cast<LayerTilemap*>(layer)->tilesetIndex() == tsi) {
553 // Set same index just to update the internal tileset pointer in
554 // LayerTilemap
555 static_cast<LayerTilemap*>(layer)->setTilesetIndex(tsi);
556 }
557 }
558}
559
560// TODO replace it with a images iterator
561void Sprite::getImages(std::vector<ImageRef>& images) const
562{
563 for (Cel* cel : uniqueCels())
564 if (cel->image()->pixelFormat() != IMAGE_TILEMAP)
565 images.push_back(cel->imageRef());
566
567 if (hasTilesets()) {
568 for (Tileset* tileset : *tilesets()) {
569 for (tile_index i=0; i<tileset->size(); ++i) {
570 ImageRef image = tileset->get(i);
571 if (image)
572 images.push_back(image);
573 }
574 }
575 }
576}
577
578void Sprite::getTilemapsByTileset(const Tileset* tileset,
579 std::vector<ImageRef>& images) const
580{
581 for (const Cel* cel : uniqueCels()) {
582 if (cel->layer()->isTilemap() &&
583 static_cast<LayerTilemap*>(cel->layer())->tileset() == tileset) {
584 images.push_back(cel->imageRef());
585 }
586 }
587}
588
589void Sprite::remapImages(const Remap& remap)
590{
591 ASSERT(pixelFormat() == IMAGE_INDEXED);
592 //ASSERT(remap.size() == 256);
593
594 std::vector<ImageRef> images;
595 getImages(images);
596 for (ImageRef& image : images)
597 remap_image(image.get(), remap);
598}
599
600void Sprite::remapTilemaps(const Tileset* tileset,
601 const Remap& remap)
602{
603 for (Cel* cel : uniqueCels()) {
604 if (cel->layer()->isTilemap() &&
605 static_cast<LayerTilemap*>(cel->layer())->tileset() == tileset) {
606 remap_image(cel->image(), remap);
607 }
608 }
609}
610
611//////////////////////////////////////////////////////////////////////
612// Drawing
613
614void Sprite::pickCels(const double x,
615 const double y,
616 const frame_t frame,
617 const int opacityThreshold,
618 const LayerList& layers,
619 CelList& cels) const
620{
621 gfx::PointF pos(x, y);
622
623 for (int i=(int)layers.size()-1; i>=0; --i) {
624 const Layer* layer = layers[i];
625
626 Cel* cel = layer->cel(frame);
627 if (!cel)
628 continue;
629
630 const Image* image = cel->image();
631 if (!image)
632 continue;
633
634 gfx::RectF celBounds;
635 if (cel->layer()->isReference())
636 celBounds = cel->boundsF();
637 else
638 celBounds = cel->bounds();
639
640 if (!celBounds.contains(pos))
641 continue;
642
643 gfx::Point ipos;
644 if (image->isTilemap()) {
645 Tileset* tileset = static_cast<LayerTilemap*>(cel->layer())->tileset();
646 if (!tileset)
647 continue;
648
649 const Grid grid = cel->grid();
650
651 tile_t tile = notile;
652 gfx::Point tilePos = grid.canvasToTile(gfx::Point(pos));
653 if (image->bounds().contains(tilePos.x, tilePos.y))
654 tile = image->getPixel(tilePos.x, tilePos.y);
655 if (tile == notile)
656 continue;
657
658 image = tileset->get(tile).get();
659 if (!image)
660 continue;
661
662 gfx::Point tileStart = grid.tileToCanvas(tilePos);
663 ipos = gfx::Point(pos.x - tileStart.x,
664 pos.y - tileStart.y);
665 }
666 else {
667 ipos = gfx::Point(
668 int((pos.x-celBounds.x)*image->width()/celBounds.w),
669 int((pos.y-celBounds.y)*image->height()/celBounds.h));
670 }
671
672 if (!image->bounds().contains(ipos))
673 continue;
674
675 const color_t color = get_pixel(image, ipos.x, ipos.y);
676 bool isOpaque = true;
677
678 switch (image->pixelFormat()) {
679 case IMAGE_RGB:
680 isOpaque = (rgba_geta(color) >= opacityThreshold);
681 break;
682 case IMAGE_INDEXED:
683 isOpaque = (color != image->maskColor());
684 break;
685 case IMAGE_GRAYSCALE:
686 isOpaque = (graya_geta(color) >= opacityThreshold);
687 break;
688 }
689
690 if (!isOpaque)
691 continue;
692
693 cels.push_back(cel);
694 }
695}
696
697//////////////////////////////////////////////////////////////////////
698// Iterators
699
700LayerList Sprite::allLayers() const
701{
702 LayerList list;
703 m_root->allLayers(list);
704 return list;
705}
706
707LayerList Sprite::allVisibleLayers() const
708{
709 LayerList list;
710 m_root->allVisibleLayers(list);
711 return list;
712}
713
714LayerList Sprite::allVisibleReferenceLayers() const
715{
716 LayerList list;
717 m_root->allVisibleReferenceLayers(list);
718 return list;
719}
720
721LayerList Sprite::allBrowsableLayers() const
722{
723 LayerList list;
724 m_root->allBrowsableLayers(list);
725 return list;
726}
727
728CelsRange Sprite::cels() const
729{
730 SelectedFrames selFrames;
731 selFrames.insert(0, lastFrame());
732 return CelsRange(this, selFrames);
733}
734
735CelsRange Sprite::cels(frame_t frame) const
736{
737 SelectedFrames selFrames;
738 selFrames.insert(frame);
739 return CelsRange(this, selFrames);
740}
741
742CelsRange Sprite::uniqueCels() const
743{
744 SelectedFrames selFrames;
745 selFrames.insert(0, lastFrame());
746 return CelsRange(this, selFrames, CelsRange::UNIQUE);
747}
748
749CelsRange Sprite::uniqueCels(const SelectedFrames& selFrames) const
750{
751 return CelsRange(this, selFrames, CelsRange::UNIQUE);
752}
753
754////////////////////////////////////////
755// Tilesets
756
757Tilesets* Sprite::tilesets() const
758{
759 if (!m_tilesets)
760 m_tilesets = new Tilesets;
761 return m_tilesets;
762}
763
764} // namespace doc
765