Fix wrong edges on Brush Preview on Tilemap Mode (fix #4176)

This commit is contained in:
Gaspar Capello 2024-01-10 11:23:17 -03:00 committed by David Capello
parent 0c7759acf1
commit e9706f106f
2 changed files with 73 additions and 21 deletions

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019-2023 Igara Studio S.A. // Copyright (C) 2019-2024 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -17,7 +17,6 @@
#include "app/color.h" #include "app/color.h"
#include "app/color_utils.h" #include "app/color_utils.h"
#include "app/doc.h" #include "app/doc.h"
#include "app/site.h"
#include "app/snap_to_grid.h" #include "app/snap_to_grid.h"
#include "app/tools/controller.h" #include "app/tools/controller.h"
#include "app/tools/ink.h" #include "app/tools/ink.h"
@ -25,7 +24,6 @@
#include "app/tools/point_shape.h" #include "app/tools/point_shape.h"
#include "app/tools/tool.h" #include "app/tools/tool.h"
#include "app/tools/tool_loop.h" #include "app/tools/tool_loop.h"
#include "app/ui/color_bar.h"
#include "app/ui/context_bar.h" #include "app/ui/context_bar.h"
#include "app/ui/editor/editor.h" #include "app/ui/editor/editor.h"
#include "app/ui/editor/tool_loop_impl.h" #include "app/ui/editor/tool_loop_impl.h"
@ -165,11 +163,14 @@ void BrushPreview::show(const gfx::Point& screenPos)
tools::Tool* tool = m_editor->getCurrentEditorTool(); tools::Tool* tool = m_editor->getCurrentEditorTool();
const bool isFloodfill = tool->getPointShape(0)->isFloodFill(); const bool isFloodfill = tool->getPointShape(0)->isFloodFill();
// TODO add support for "tile-brushes"
// Get current tilemap mode
const TilemapMode tilemapMode = site.tilemapMode();
gfx::Rect origBrushBounds = gfx::Rect origBrushBounds =
((isFloodfill && brush->type() != BrushType::kImageBrushType) || ((isFloodfill && brush->type() != BrushType::kImageBrushType) ||
site.tilemapMode() == TilemapMode::Tiles ? gfx::Rect(0, 0, 1, 1) tilemapMode == TilemapMode::Tiles ? gfx::Rect(0, 0, 1, 1)
: brush->bounds()); : brush->bounds());
gfx::Rect brushBounds = origBrushBounds; gfx::Rect brushBounds = origBrushBounds;
// Cursor in the screen (view) // Cursor in the screen (view)
@ -188,9 +189,6 @@ void BrushPreview::show(const gfx::Point& screenPos)
// Get the current tool // Get the current tool
tools::Ink* ink = m_editor->getCurrentEditorInk(); tools::Ink* ink = m_editor->getCurrentEditorInk();
// Get current tilemap mode
TilemapMode tilemapMode = ColorBar::instance()->tilemapMode();
// Setup the cursor type depending on several factors (current tool, // Setup the cursor type depending on several factors (current tool,
// foreground color, layer transparency, brush size, etc.). // foreground color, layer transparency, brush size, etc.).
color_t brush_color = getBrushColor(sprite, layer); color_t brush_color = getBrushColor(sprite, layer);
@ -267,6 +265,12 @@ void BrushPreview::show(const gfx::Point& screenPos)
break; break;
} }
// For tiles as we show the edges of the tile, we add the crosshair
// in the mouse position as a helper.
if (m_type & BRUSH_BOUNDARIES &&
tilemapMode == TilemapMode::Tiles)
m_type |= CROSSHAIR;
if (m_type & SELECTION_CROSSHAIR) if (m_type & SELECTION_CROSSHAIR)
showPreview = false; showPreview = false;
@ -293,7 +297,7 @@ void BrushPreview::show(const gfx::Point& screenPos)
m_type &= ~BRUSH_BOUNDARIES; m_type &= ~BRUSH_BOUNDARIES;
} }
if (m_type & BRUSH_BOUNDARIES) if (m_type & BRUSH_BOUNDARIES)
generateBoundaries(); generateBoundaries(site, spritePos);
// Draw pixel/brush preview // Draw pixel/brush preview
if (showPreview) { if (showPreview) {
@ -321,7 +325,7 @@ void BrushPreview::show(const gfx::Point& screenPos)
} }
gfx::Rect extraCelBounds; gfx::Rect extraCelBounds;
if (site.tilemapMode() == TilemapMode::Tiles) { if (tilemapMode == TilemapMode::Tiles) {
ASSERT(layer->isTilemap()); ASSERT(layer->isTilemap());
doc::Grid grid = site.grid(); doc::Grid grid = site.grid();
extraCelBounds = grid.canvasToTile(extraCelBoundsInCanvas); extraCelBounds = grid.canvasToTile(extraCelBoundsInCanvas);
@ -347,7 +351,7 @@ void BrushPreview::show(const gfx::Point& screenPos)
m_extraCel.reset(new ExtraCel); m_extraCel.reset(new ExtraCel);
m_extraCel->create( m_extraCel->create(
site.tilemapMode(), tilemapMode,
document->sprite(), document->sprite(),
extraCelBoundsInCanvas, extraCelBoundsInCanvas,
extraCelBounds.size(), extraCelBounds.size(),
@ -432,6 +436,9 @@ void BrushPreview::show(const gfx::Point& screenPos)
if (m_type & NATIVE_CROSSHAIR) if (m_type & NATIVE_CROSSHAIR)
ui::set_mouse_cursor(ui::kCrosshairCursor); ui::set_mouse_cursor(ui::kCrosshairCursor);
m_lastLayer = site.layer();
m_lastTilemapMode = tilemapMode;
} }
// Cleans the brush cursor from the specified editor. // Cleans the brush cursor from the specified editor.
@ -512,13 +519,38 @@ void BrushPreview::invalidateRegion(const gfx::Region& region)
m_clippingRegion.createSubtraction(m_clippingRegion, region); m_clippingRegion.createSubtraction(m_clippingRegion, region);
} }
void BrushPreview::generateBoundaries() void BrushPreview::calculateTileBoundariesOrigin(const doc::Grid& grid,
const gfx::Point& spritePos)
{
m_brushBoundaries.offset(-m_brushBoundaries.begin()[0].bounds().x,
-m_brushBoundaries.begin()[0].bounds().y);
gfx::Point canvasPos = grid.tileToCanvas(grid.canvasToTile(spritePos));
m_brushBoundaries.offset(canvasPos.x - spritePos.x,
canvasPos.y - spritePos.y);
}
void BrushPreview::generateBoundaries(const Site& site,
const gfx::Point& spritePos)
{ {
BrushRef brush = getCurrentBrush(); BrushRef brush = getCurrentBrush();
Layer* currentLayer = site.layer();
TilemapMode tilemapMode = site.tilemapMode();
if (!m_brushBoundaries.isEmpty() && if (tilemapMode == TilemapMode::Pixels &&
m_brushGen == brush->gen()) tilemapMode == m_lastTilemapMode &&
!m_brushBoundaries.isEmpty() &&
m_brushGen == brush->gen()) {
return; return;
}
else if (tilemapMode == TilemapMode::Tiles &&
tilemapMode == m_lastTilemapMode &&
m_lastLayer == currentLayer) {
// When tilemapMode is 'Tiles' is needed an offset
// re-calculation of the brush boundaries, even
// if it's no need to update the mask.
calculateTileBoundariesOrigin(site.grid(), spritePos);
return;
}
const bool isOnePixel = const bool isOnePixel =
(m_editor->getCurrentEditorTool()->getPointShape(0)->isPixel() || (m_editor->getCurrentEditorTool()->getPointShape(0)->isPixel() ||
@ -528,7 +560,13 @@ void BrushPreview::generateBoundaries()
Image* mask = nullptr; Image* mask = nullptr;
bool deleteMask = true; bool deleteMask = true;
if (isOnePixel) { if (tilemapMode == TilemapMode::Tiles) {
mask = Image::create(IMAGE_BITMAP,
site.grid().tileSize().w,
site.grid().tileSize().h);
mask->clear((color_t)1);
}
else if (isOnePixel) {
mask = Image::create(IMAGE_BITMAP, 1, 1); mask = Image::create(IMAGE_BITMAP, 1, 1);
mask->putPixel(0, 0, (color_t)1); mask->putPixel(0, 0, (color_t)1);
} }
@ -539,9 +577,13 @@ void BrushPreview::generateBoundaries()
} }
m_brushBoundaries.regen(mask ? mask: brushImage); m_brushBoundaries.regen(mask ? mask: brushImage);
if (!isOnePixel) if (tilemapMode == TilemapMode::Pixels) {
m_brushBoundaries.offset(-brush->center().x, if (!isOnePixel)
-brush->center().y); m_brushBoundaries.offset(-brush->center().x,
-brush->center().y);
}
else
calculateTileBoundariesOrigin(site.grid(), spritePos);
if (deleteMask) if (deleteMask)
delete mask; delete mask;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019-2021 Igara Studio S.A. // Copyright (C) 2019-2024 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -34,6 +34,7 @@ namespace ui {
namespace app { namespace app {
class Editor; class Editor;
class Site;
class BrushPreview { class BrushPreview {
public: public:
@ -90,7 +91,13 @@ namespace app {
doc::BrushRef getCurrentBrush(); doc::BrushRef getCurrentBrush();
static doc::color_t getBrushColor(doc::Sprite* sprite, doc::Layer* layer); static doc::color_t getBrushColor(doc::Sprite* sprite, doc::Layer* layer);
void generateBoundaries(); // Offset re-calculation of brush boundaries only for TilemapMode::Tiles.
// Used within 'generateBoundaries' function.
void calculateTileBoundariesOrigin(const doc::Grid& grid,
const gfx::Point& spritePos);
void generateBoundaries(const Site& site,
const gfx::Point& spritePos);
// Creates a little native cursor to draw the CROSSHAIR // Creates a little native cursor to draw the CROSSHAIR
void createCrosshairCursor(ui::Graphics* g, const gfx::Color cursorColor); void createCrosshairCursor(ui::Graphics* g, const gfx::Color cursorColor);
@ -141,6 +148,9 @@ namespace app {
gfx::Rect m_lastBounds; gfx::Rect m_lastBounds;
doc::frame_t m_lastFrame; doc::frame_t m_lastFrame;
doc::Layer* m_lastLayer = nullptr;
TilemapMode m_lastTilemapMode;
ExtraCelRef m_extraCel; ExtraCelRef m_extraCel;
}; };