Skip to content

Commit

Permalink
Fix wrong alignment between mouse and sensor threshold position (fix a…
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap authored and Gasparoken committed May 6, 2024
1 parent 12d8135 commit 9619559
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 72 deletions.
15 changes: 4 additions & 11 deletions src/app/commands/cmd_change_brush.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Aseprite
// Copyright (c) 2023 Igara Studio S.A.
// Copyright (c) 2023-2024 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
Expand Down Expand Up @@ -156,9 +156,7 @@ void ChangeBrushCommand::onExecute(Context* context)

// Create a copy of the brush (to avoid modifying the original
// brush from the AppBrushes stock)
BrushRef newBrush = std::make_shared<Brush>(*brush);
newBrush->setImage(newImg.get(),
newMsk.get());
BrushRef newBrush = brush->cloneWithExistingImages(newImg, newMsk);
contextBar->setActiveBrush(newBrush);
}
else {
Expand Down Expand Up @@ -210,9 +208,7 @@ void ChangeBrushCommand::onExecute(Context* context)
break;
}

BrushRef newBrush = std::make_shared<Brush>(*brush);
newBrush->setImage(newImg.get(),
newMsk.get());
BrushRef newBrush = brush->cloneWithExistingImages(newImg, newMsk);
contextBar->setActiveBrush(newBrush);
}
else {
Expand Down Expand Up @@ -297,10 +293,7 @@ void ChangeBrushCommand::onExecute(Context* context)

ImageRef newImg2(crop_image(newImg.get(), cropBounds, bg));
ImageRef newMsk2(crop_image(newMsk.get(), cropBounds, bg));

BrushRef newBrush = std::make_shared<Brush>(*brush);
newBrush->setImage(newImg.get(),
newMsk.get());
BrushRef newBrush = brush->cloneWithExistingImages(newImg2, newMsk2);
contextBar->setActiveBrush(newBrush);
}
break;
Expand Down
4 changes: 2 additions & 2 deletions src/app/script/brush_class.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2019-2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
Expand Down Expand Up @@ -36,7 +36,7 @@ BrushRef Brush_new(lua_State* L, int index)
if (auto brush2 = may_get_obj<BrushObj>(L, index)) {
ASSERT(brush2->brush);
if (brush2->brush)
brush.reset(new Brush(*brush2->brush));
brush = brush2->brush->cloneWithNewImages();
}
else if (auto image = may_get_image_from_arg(L, index)) {
if (image) {
Expand Down
9 changes: 5 additions & 4 deletions src/app/tools/tool_loop_manager.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2023 Igara Studio S.A.
// Copyright (C) 2019-2024 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
Expand Down Expand Up @@ -44,7 +44,8 @@ using namespace filters;
ToolLoopManager::ToolLoopManager(ToolLoop* toolLoop)
: m_toolLoop(toolLoop)
, m_canceled(false)
, m_brush0(*toolLoop->getBrush())
, m_brushSize0(toolLoop->getBrush()->size())
, m_brushAngle0(toolLoop->getBrush()->angle())
, m_dynamics(toolLoop->getDynamics())
{
}
Expand Down Expand Up @@ -358,8 +359,8 @@ Stroke::Pt ToolLoopManager::getSpriteStrokePt(const Pointer& pointer)
{
// Convert the screen point to a sprite point
Stroke::Pt spritePoint = pointer.point();
spritePoint.size = m_brush0.size();
spritePoint.angle = m_brush0.angle();
spritePoint.size = m_brushSize0;
spritePoint.angle = m_brushAngle0;

// Center the input to some grid point if needed
snapToGrid(spritePoint);
Expand Down
5 changes: 3 additions & 2 deletions src/app/tools/tool_loop_manager.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2019-2024 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
Expand Down Expand Up @@ -95,7 +95,8 @@ class ToolLoopManager {
Pointer m_lastPointer;
gfx::Region m_dirtyArea;
gfx::Region m_nextDirtyArea;
doc::Brush m_brush0;
const int m_brushSize0;
const int m_brushAngle0;
DynamicsOptions m_dynamics;
gfx::PointF m_stabilizerCenter;
};
Expand Down
4 changes: 3 additions & 1 deletion src/app/ui/brush_popup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,9 @@ os::SurfaceRef BrushPopup::createSurfaceForBrush(const BrushRef& origBrush,
BrushRef brush = origBrush;
if (brush) {
if (brush->type() != kImageBrushType && brush->size() > kMaxSize) {
brush.reset(new Brush(*brush));
// Clone with shared images, as setSize() will re-create the
// images and the brush is no kImageBrushType anyway.
brush = brush->cloneWithSharedImages();
brush->setSize(kMaxSize);
}
// Show the original image in the popup (without the image colors
Expand Down
6 changes: 4 additions & 2 deletions src/app/ui/dynamics_popup.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020-2023 Igara Studio S.A.
// Copyright (C) 2020-2024 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
Expand Down Expand Up @@ -166,7 +166,9 @@ class DynamicsPopup::ThresholdSlider : public Widget {
break;

auto mouseMsg = static_cast<MouseMessage*>(msg);
const gfx::Rect rc = bounds();
gfx::Rect rc = bounds();
rc.shrink(border());
rc.shrink(gfx::Border(3, 0, 3, 1) * guiscale());
float u = (mouseMsg->position().x - rc.x) / float(rc.w);
u = std::clamp(u, 0.0f, 1.0f);
switch (capture) {
Expand Down
29 changes: 22 additions & 7 deletions src/app/ui/editor/tool_loop_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,31 @@ class ToolLoopBase : public tools::ToolLoop {
ASSERT(m_ink);
ASSERT(m_controller);

if (m_brush->type() == kImageBrushType &&
(m_button == Right || (m_button == Left && m_brush->isMonochromeImage()))) {
m_brush->setImageColor(
Brush::ImageColor::MainColor,
// If the user right-clicks with a custom/image brush we change
// the image's colors of the brush to the background color.
//
// This is different from SwitchColors that makes a new brush
// switching fg <-> bg colors, so here we have some extra
// functionality with custom brushes (quickly convert the custom
// brush with a plain color, or in other words, replace the custom
// brush area with the background color).
if (m_brush->type() == kImageBrushType && m_button == Right) {
// We've to recalculate the background color to use for the
// brush using the specific brush image pixel format/color mode,
// as we cannot use m_primaryColor or m_bgColor here because
// those are in the sprite pixel format/color mode.
const color_t brushColor =
color_utils::color_for_target_mask(
(m_button == Left ? Preferences::instance().colorBar.fgColor() :
Preferences::instance().colorBar.bgColor()),
Preferences::instance().colorBar.bgColor(),
ColorTarget(ColorTarget::TransparentLayer,
m_brush->image()->pixelFormat(),
-1)));
-1));

// Clone the brush with new images to avoid modifying the
// current brush used in left-click / brush preview.
BrushRef newBrush = m_brush->cloneWithNewImages();
newBrush->setImageColor(Brush::ImageColor::BothColors, brushColor);
m_brush = newBrush;
}

if (m_tilesMode) {
Expand Down
100 changes: 69 additions & 31 deletions src/doc/brush.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (C) 2019-2023 Igara Studio S.A.
// Copyright (C) 2019-2024 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
Expand Down Expand Up @@ -48,32 +48,43 @@ Brush::Brush(BrushType type, int size, int angle)
regenerate();
}

Brush::Brush(const Brush& brush)
Brush::~Brush()
{
m_type = brush.m_type;
m_size = brush.m_size;
m_angle = brush.m_angle;
m_image = brush.m_image;
m_maskBitmap = brush.m_maskBitmap;
m_pattern = brush.m_pattern;
m_patternOrigin = brush.m_patternOrigin;
m_gen = 0;
clean();
}

regenerate();
BrushRef Brush::cloneWithSharedImages() const
{
BrushRef newBrush = std::make_shared<Brush>();
newBrush->copyFieldsFromBrush(*this);
return newBrush;
}

Brush::~Brush()
BrushRef Brush::cloneWithNewImages() const
{
clean();
BrushRef newBrush = std::make_shared<Brush>();
newBrush->copyFieldsFromBrush(*this);
if (newBrush->m_image)
newBrush->m_image.reset(Image::createCopy(newBrush->m_image.get()));
if (newBrush->m_maskBitmap)
newBrush->m_maskBitmap.reset(Image::createCopy(newBrush->m_maskBitmap.get()));
return newBrush;
}

void Brush::setType(BrushType type)
BrushRef Brush::cloneWithExistingImages(const ImageRef& image,
const ImageRef& maskBitmap) const
{
m_type = type;
if (m_type != kImageBrushType)
regenerate();
BrushRef newBrush = std::make_shared<Brush>();
newBrush->copyFieldsFromBrush(*this);

newBrush->m_image = image;
if (maskBitmap)
newBrush->m_maskBitmap = maskBitmap;
else
clean();
newBrush->regenerateMaskBitmap();

newBrush->resetBounds();
return newBrush;
}

void Brush::setSize(int size)
Expand All @@ -95,16 +106,8 @@ void Brush::setImage(const Image* image,
m_image.reset(Image::createCopy(image));
if (maskBitmap)
m_maskBitmap.reset(Image::createCopy(maskBitmap));
else {
int w = image->width();
int h = image->height();
m_maskBitmap.reset(Image::create(IMAGE_BITMAP, w, h));
LockImageBits<BitmapTraits> bits(m_maskBitmap.get());
auto pos = bits.begin();
for (int v=0; v<h; ++v)
for (int u=0; u<w; ++u, ++pos)
*pos = (get_pixel(image, u, v) != image->maskColor());
}
else
regenerateMaskBitmap();

m_backupImage.reset();
m_mainColor.reset();
Expand Down Expand Up @@ -234,7 +237,8 @@ static void replace_image_colors_indexed(
}
}

void Brush::setImageColor(ImageColor imageColor, color_t color)
void Brush::setImageColor(const ImageColor imageColor,
const color_t color)
{
ASSERT(m_image);
if (!m_image)
Expand All @@ -249,10 +253,13 @@ void Brush::setImageColor(ImageColor imageColor, color_t color)

switch (imageColor) {
case ImageColor::MainColor:
m_mainColor = color_t(color);
m_mainColor = color;
break;
case ImageColor::BackgroundColor:
m_bgColor = color_t(color);
m_bgColor = color;
break;
case ImageColor::BothColors:
m_mainColor = m_bgColor = color;
break;
}

Expand Down Expand Up @@ -379,6 +386,22 @@ void Brush::regenerate()
}
}

void Brush::regenerateMaskBitmap()
{
ASSERT(m_image);
if (!m_image)
return;

int w = m_image->width();
int h = m_image->height();
m_maskBitmap.reset(Image::create(IMAGE_BITMAP, w, h));
LockImageBits<BitmapTraits> bits(m_maskBitmap.get());
auto pos = bits.begin();
for (int v=0; v<h; ++v)
for (int u=0; u<w; ++u, ++pos)
*pos = (get_pixel(m_image.get(), u, v) != m_image->maskColor());
}

void Brush::resetBounds()
{
m_center = gfx::Point(std::max(0, m_image->width()/2),
Expand All @@ -388,4 +411,19 @@ void Brush::resetBounds()
m_image->height()));
}

void Brush::copyFieldsFromBrush(const Brush& brush)
{
m_type = brush.m_type;
m_size = brush.m_size;
m_angle = brush.m_angle;
m_image = brush.m_image;
m_maskBitmap = brush.m_maskBitmap;
m_bounds = brush.m_bounds;
m_center = brush.m_center;
m_pattern = brush.m_pattern;
m_patternOrigin = brush.m_patternOrigin;
m_patternImage = brush.m_patternImage;
m_gen = 0;
}

} // namespace doc
Loading

0 comments on commit 9619559

Please sign in to comment.