mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-29 03:32:48 +00:00
Add image buffers and mask to apply symmetry to image brushes
This commit is contained in:
parent
9e396227c2
commit
053a538272
@ -13,6 +13,7 @@
|
||||
|
||||
#include "base/pi.h"
|
||||
#include "doc/algo.h"
|
||||
#include "doc/algorithm/flip_image.h"
|
||||
#include "doc/algorithm/polygon.h"
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/image.h"
|
||||
@ -286,6 +287,7 @@ void Brush::setImageColor(const ImageColor imageColor,
|
||||
(m_bgColor ? true: false), (m_bgColor ? *m_bgColor: 0));
|
||||
break;
|
||||
}
|
||||
resetSymmetries();
|
||||
}
|
||||
|
||||
void Brush::resetImageColors()
|
||||
@ -319,6 +321,133 @@ static void algo_hline(int x1, int y, int x2, void *data)
|
||||
draw_hline(reinterpret_cast<Image*>(data), x1, y, x2, BitmapTraits::max_value);
|
||||
}
|
||||
|
||||
void Brush::resetSymmetries()
|
||||
{
|
||||
m_symmetryImages.resize(0);
|
||||
m_symmetryMasks.resize(0);
|
||||
}
|
||||
|
||||
void Brush::reserveSymmetries()
|
||||
{
|
||||
m_symmetryImages.resize(int(SymmetryIndex::ELEMENTS));
|
||||
m_symmetryMasks.resize(int(SymmetryIndex::ELEMENTS));
|
||||
}
|
||||
|
||||
Image* Brush::getSymmetryImage(const SymmetryIndex index)
|
||||
{
|
||||
if (index <= SymmetryIndex::ORIGINAL ||
|
||||
index >= SymmetryIndex::ELEMENTS)
|
||||
return m_image.get();
|
||||
|
||||
if (m_symmetryImages.empty())
|
||||
reserveSymmetries();
|
||||
|
||||
const int i = int(index);
|
||||
if (!m_symmetryImages[i]) {
|
||||
switch (index) {
|
||||
case SymmetryIndex::FLIPPED_X:
|
||||
case SymmetryIndex::FLIPPED_Y: {
|
||||
const doc::algorithm::FlipType flip =
|
||||
(index == SymmetryIndex::FLIPPED_X ? doc::algorithm::FlipType::FlipHorizontal:
|
||||
doc::algorithm::FlipType::FlipVertical);
|
||||
if (m_image) {
|
||||
std::unique_ptr<Image> tempImage(Image::createCopy(m_image.get()));
|
||||
|
||||
doc::algorithm::flip_image(tempImage.get(), tempImage->bounds(), flip);
|
||||
m_symmetryImages[i].reset(tempImage.release());
|
||||
}
|
||||
if (m_maskBitmap && !m_symmetryMasks[i]) {
|
||||
std::unique_ptr<Image> tempImage(Image::createCopy(m_maskBitmap.get()));
|
||||
doc::algorithm::flip_image(tempImage.get(), tempImage->bounds(), flip);
|
||||
m_symmetryMasks[i].reset(tempImage.release());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SymmetryIndex::FLIPPED_XY: {
|
||||
if (m_image) {
|
||||
std::unique_ptr<Image> tempImage(Image::createCopy(m_image.get()));
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipVertical);
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipHorizontal);
|
||||
m_symmetryImages[i].reset(tempImage.release());
|
||||
}
|
||||
if (m_maskBitmap && !m_symmetryMasks[i]) {
|
||||
std::unique_ptr<Image> tempImage(Image::createCopy(m_maskBitmap.get()));
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipVertical);
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipHorizontal);
|
||||
m_symmetryMasks[i].reset(tempImage.release());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SymmetryIndex::ROT_FLIP_90:
|
||||
case SymmetryIndex::ROT_FLIP_270: {
|
||||
const double angle = (index == SymmetryIndex::ROT_FLIP_90? 90.0 : -90.0);
|
||||
if (m_image) {
|
||||
std::unique_ptr<Image> tempImage(
|
||||
Image::create(m_image->pixelFormat(),
|
||||
m_image->height(),
|
||||
m_image->width()));
|
||||
rotate_image(m_image.get(), tempImage.get(), angle);
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipHorizontal);
|
||||
m_symmetryImages[i].reset(tempImage.release());
|
||||
}
|
||||
if (m_maskBitmap && !m_symmetryMasks[i]) {
|
||||
std::unique_ptr<Image> tempImage(
|
||||
Image::create(m_maskBitmap->pixelFormat(),
|
||||
m_maskBitmap->height(),
|
||||
m_maskBitmap->width()));
|
||||
rotate_image(m_maskBitmap.get(), tempImage.get(), angle);
|
||||
doc::algorithm::flip_image(tempImage.get(),
|
||||
tempImage->bounds(),
|
||||
doc::algorithm::FlipType::FlipHorizontal);
|
||||
m_symmetryMasks[i].reset(tempImage.release());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SymmetryIndex::ROTATED_90:
|
||||
case SymmetryIndex::ROTATED_270: {
|
||||
const double angle = (index == SymmetryIndex::ROTATED_90? 90.0 : -90.0);
|
||||
if (m_image) {
|
||||
std::unique_ptr<Image> tempImage(
|
||||
Image::create(m_image.get()->pixelFormat(),
|
||||
m_image.get()->height(),
|
||||
m_image.get()->width()));
|
||||
rotate_image(m_image.get(), tempImage.get(), angle);
|
||||
m_symmetryImages[i].reset(tempImage.release());
|
||||
}
|
||||
if (m_maskBitmap && !m_symmetryMasks[i]) {
|
||||
std::unique_ptr<Image> tempImage(
|
||||
Image::create(m_maskBitmap->pixelFormat(),
|
||||
m_maskBitmap->height(),
|
||||
m_maskBitmap->width()));
|
||||
rotate_image(m_maskBitmap.get(), tempImage.get(), angle);
|
||||
m_symmetryMasks[i].reset(tempImage.release());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_symmetryImages[i].get();
|
||||
}
|
||||
|
||||
Image* Brush::getSymmetryMask(const SymmetryIndex index)
|
||||
{
|
||||
if (index <= SymmetryIndex::ORIGINAL ||
|
||||
index >= SymmetryIndex::ELEMENTS)
|
||||
return m_maskBitmap.get();
|
||||
|
||||
getSymmetryImage(index); // Update Image and Mask symmetry buffers
|
||||
return m_symmetryMasks[int(index)].get();
|
||||
}
|
||||
|
||||
// Regenerates the brush bitmap and its rectangle's region.
|
||||
void Brush::regenerate()
|
||||
{
|
||||
|
@ -22,6 +22,18 @@
|
||||
|
||||
namespace doc {
|
||||
|
||||
enum class SymmetryIndex {
|
||||
ORIGINAL = 0,
|
||||
FLIPPED_X = 1,
|
||||
FLIPPED_Y = 2,
|
||||
FLIPPED_XY = 3,
|
||||
ROTATED_270 = 4,
|
||||
ROT_FLIP_90 = 5,
|
||||
ROTATED_90 = 6,
|
||||
ROT_FLIP_270 = 7,
|
||||
ELEMENTS = 8
|
||||
};
|
||||
|
||||
class Brush;
|
||||
using BrushRef = std::shared_ptr<Brush>;
|
||||
|
||||
@ -93,6 +105,11 @@ namespace doc {
|
||||
return m_image.get();
|
||||
}
|
||||
|
||||
void resetSymmetries();
|
||||
void reserveSymmetries();
|
||||
Image* getSymmetryImage(const SymmetryIndex index);
|
||||
Image* getSymmetryMask(const SymmetryIndex index);
|
||||
|
||||
private:
|
||||
void clean();
|
||||
void regenerate();
|
||||
@ -112,6 +129,10 @@ namespace doc {
|
||||
ImageRef m_patternImage;
|
||||
int m_gen;
|
||||
|
||||
//Symmetry image/mask buffers
|
||||
std::vector<ImageRef> m_symmetryImages;
|
||||
std::vector<ImageRef> m_symmetryMasks;
|
||||
|
||||
// Extra data used for setImageColor()
|
||||
ImageRef m_backupImage; // Backup image to avoid losing original brush colors/pattern
|
||||
std::optional<color_t> m_mainColor; // Main image brush color
|
||||
|
Loading…
x
Reference in New Issue
Block a user