mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-22 06:41:08 +00:00
Fix bounds calculation on tiles drawing outside cel bounds and the filling tile index is tile_i_notile, instead of empty tile.
This commit is contained in:
parent
2ffac6803c
commit
a195487fc0
@ -1,6 +1,6 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2016 David Capello
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/layer_tilemap.h"
|
||||
#include "doc/primitives.h"
|
||||
|
||||
namespace app {
|
||||
@ -24,9 +25,7 @@ CropCel::CropCel(Cel* cel, const gfx::Rect& newBounds)
|
||||
: WithCel(cel)
|
||||
, m_oldOrigin(cel->position())
|
||||
, m_newOrigin(newBounds.origin())
|
||||
// Instead of using cel->bounds() we use the image size because it
|
||||
// works for tilemaps too.
|
||||
, m_oldBounds(cel->position(), cel->image()->size())
|
||||
, m_oldBounds(cel->bounds())
|
||||
, m_newBounds(newBounds)
|
||||
{
|
||||
m_oldBounds.offset(-m_newOrigin);
|
||||
@ -51,10 +50,18 @@ void CropCel::cropImage(const gfx::Point& origin,
|
||||
{
|
||||
Cel* cel = this->cel();
|
||||
|
||||
gfx::Rect localBounds(bounds);
|
||||
if (cel->layer()->isTilemap()) {
|
||||
doc::Tileset* tileset = static_cast<LayerTilemap*>(cel->layer())->tileset();
|
||||
if (tileset) {
|
||||
doc::Grid grid = tileset->grid();
|
||||
localBounds = grid.canvasToTile(bounds);
|
||||
}
|
||||
}
|
||||
if (bounds != cel->image()->bounds()) {
|
||||
ImageRef image(crop_image(cel->image(),
|
||||
bounds.x, bounds.y,
|
||||
bounds.w, bounds.h,
|
||||
localBounds.x, localBounds.y,
|
||||
localBounds.w, localBounds.h,
|
||||
cel->image()->maskColor()));
|
||||
ObjectId id = cel->image()->id();
|
||||
ObjectVersion ver = cel->image()->version();
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -14,6 +15,7 @@
|
||||
#include "app/cmd/crop_cel.h"
|
||||
#include "app/cmd/trim_cel.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/layer_tilemap.h"
|
||||
|
||||
namespace app {
|
||||
namespace cmd {
|
||||
@ -36,17 +38,35 @@ void PatchCel::onExecute()
|
||||
{
|
||||
Cel* cel = this->cel();
|
||||
|
||||
const gfx::Rect newBounds =
|
||||
cel->bounds() | gfx::Rect(m_region.bounds()).offset(m_pos);
|
||||
gfx::Rect newBounds;
|
||||
gfx::Region copyRegion = m_region;
|
||||
Tileset* tileset = nullptr;
|
||||
doc::Grid grid;
|
||||
if (cel->image()->pixelFormat() == IMAGE_TILEMAP ) {
|
||||
newBounds = cel->bounds() | m_region.bounds();
|
||||
tileset = static_cast<LayerTilemap*>(cel->layer())->tileset();
|
||||
grid = tileset->grid();
|
||||
grid.origin(m_pos);
|
||||
copyRegion = grid.canvasToTile(m_region);
|
||||
}
|
||||
else
|
||||
newBounds = cel->bounds() | gfx::Rect(m_region.bounds()).offset(m_pos);
|
||||
if (cel->bounds() != newBounds) {
|
||||
executeAndAdd(new CropCel(cel, newBounds));
|
||||
}
|
||||
|
||||
executeAndAdd(
|
||||
new CopyRegion(cel->image(),
|
||||
m_patch,
|
||||
m_region,
|
||||
m_pos - cel->position()));
|
||||
if (cel->image()->pixelFormat() == IMAGE_TILEMAP)
|
||||
executeAndAdd(
|
||||
new CopyRegion(cel->image(),
|
||||
m_patch,
|
||||
copyRegion,
|
||||
-grid.canvasToTile(cel->position())));
|
||||
else
|
||||
executeAndAdd(
|
||||
new CopyRegion(cel->image(),
|
||||
m_patch,
|
||||
copyRegion,
|
||||
m_pos - cel->position()));
|
||||
|
||||
executeAndAdd(new TrimCel(cel));
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "doc/image.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/tile.h"
|
||||
#include "gfx/hsl.h"
|
||||
#include "gfx/hsv.h"
|
||||
#include "gfx/rgb.h"
|
||||
@ -83,7 +84,7 @@ Color Color::fromGray(int g, int a)
|
||||
// static
|
||||
Color Color::fromIndex(int index)
|
||||
{
|
||||
ASSERT(index >= 0);
|
||||
ASSERT(index >= 0 || index == tile_i_notile);
|
||||
|
||||
Color color(Color::IndexType);
|
||||
color.m_value.index = index;
|
||||
@ -114,6 +115,7 @@ Color Color::fromImage(PixelFormat pixelFormat, color_t c)
|
||||
break;
|
||||
|
||||
case IMAGE_INDEXED:
|
||||
case IMAGE_TILEMAP:
|
||||
color = Color::fromIndex(c);
|
||||
break;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -270,7 +270,8 @@ bool DocApi::cropCel(LayerImage* layer,
|
||||
crop_image(image,
|
||||
paintPos.x, paintPos.y,
|
||||
newCelBounds.w, newCelBounds.h,
|
||||
m_document->bgColor(layer)));
|
||||
image->pixelFormat() == IMAGE_TILEMAP ?
|
||||
tile_i_notile : m_document->bgColor(layer)));
|
||||
|
||||
// Try to shrink the image ignoring transparent borders
|
||||
gfx::Rect frameBounds;
|
||||
@ -283,7 +284,8 @@ bool DocApi::cropCel(LayerImage* layer,
|
||||
crop_image(newImage.get(),
|
||||
frameBounds.x, frameBounds.y,
|
||||
frameBounds.w, frameBounds.h,
|
||||
m_document->bgColor(layer)));
|
||||
image->pixelFormat() == IMAGE_TILEMAP ?
|
||||
tile_i_notile : m_document->bgColor(layer)));
|
||||
|
||||
newCelPos += frameBounds.origin();
|
||||
}
|
||||
|
@ -78,8 +78,18 @@ Grid Site::grid() const
|
||||
{
|
||||
if (m_layer && m_layer->isTilemap()) {
|
||||
doc::Grid grid = static_cast<LayerTilemap*>(m_layer)->tileset()->grid();
|
||||
if (const Cel* cel = m_layer->cel(m_frame))
|
||||
grid.origin(grid.origin() + cel->position());
|
||||
if (const Cel* cel = m_layer->cel(m_frame)) {
|
||||
gfx::Point gridOrigin(0, 0);
|
||||
int remainderX = cel->position().x % grid.tileSize().w;
|
||||
int remainderY = cel->position().y % grid.tileSize().h;
|
||||
|
||||
if (remainderX)
|
||||
gridOrigin.x = remainderX - (remainderX > 0 ? grid.tileSize().w : 0);
|
||||
if (remainderY)
|
||||
gridOrigin.y = remainderY - (remainderY > 0 ? grid.tileSize().h : 0);
|
||||
|
||||
grid.origin(gridOrigin);
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,8 @@ public:
|
||||
const doc::Grid& grid = loop->getGrid();
|
||||
gfx::Point newPos = grid.canvasToTile(pt.toPoint());
|
||||
|
||||
if (loop->getInk()->needsCelCoordinates())
|
||||
newPos += loop->getCelOrigin();
|
||||
loop->getInk()->prepareForPointShape(loop, true, newPos.x, newPos.y);
|
||||
doInkHline(newPos.x, newPos.y, newPos.x, loop);
|
||||
}
|
||||
|
@ -225,41 +225,55 @@ void BrushPreview::show(const gfx::Point& screenPos)
|
||||
Site site = m_editor->getSite();
|
||||
|
||||
// TODO add support for "tile-brushes"
|
||||
gfx::Rect origBrushBounds =
|
||||
(isFloodfill || site.tilemapMode() == TilemapMode::Tiles ? gfx::Rect(0, 0, 1, 1):
|
||||
brush->bounds());
|
||||
gfx::Rect brushBounds = origBrushBounds;
|
||||
brushBounds.offset(spritePos);
|
||||
gfx::Rect extraCelBounds = brushBounds;
|
||||
gfx::Rect origBrushBounds;
|
||||
gfx::Rect brushBounds;
|
||||
doc::Grid grid;
|
||||
if (isFloodfill) {
|
||||
origBrushBounds = gfx::Rect(0, 0, 1, 1);
|
||||
brushBounds = origBrushBounds;
|
||||
brushBounds.offset(spritePos);
|
||||
}
|
||||
else if (site.tilemapMode() == TilemapMode::Tiles) {
|
||||
grid = site.grid();
|
||||
brushBounds = gfx::Rect(grid.tileSize());
|
||||
gfx::Point tileInGrid = grid.canvasToTile(spritePos);
|
||||
brushBounds.offset(grid.tileBoundsInCanvas(tileInGrid).origin());
|
||||
origBrushBounds.setOrigin(brushBounds.origin());
|
||||
}
|
||||
else {
|
||||
origBrushBounds = brush->bounds();
|
||||
brushBounds = origBrushBounds;
|
||||
brushBounds.offset(spritePos);
|
||||
}
|
||||
gfx::Rect extraCelBoundsInCanvas = brushBounds;
|
||||
|
||||
// Tiled mode might require a bigger extra cel (to show the tiled)
|
||||
if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::X_AXIS)) {
|
||||
brushBounds.x = wrap_value(brushBounds.x, sprite->width());
|
||||
extraCelBounds.x = brushBounds.x;
|
||||
if ((extraCelBounds.x < 0 && extraCelBounds.x2() > 0) ||
|
||||
(extraCelBounds.x < sprite->width() && extraCelBounds.x2() > sprite->width())) {
|
||||
extraCelBounds.x = 0;
|
||||
extraCelBounds.w = sprite->width();
|
||||
extraCelBoundsInCanvas.x = brushBounds.x;
|
||||
if ((extraCelBoundsInCanvas.x < 0 && extraCelBoundsInCanvas.x2() > 0) ||
|
||||
(extraCelBoundsInCanvas.x < sprite->width() && extraCelBoundsInCanvas.x2() > sprite->width())) {
|
||||
extraCelBoundsInCanvas.x = 0;
|
||||
extraCelBoundsInCanvas.w = sprite->width();
|
||||
}
|
||||
}
|
||||
if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::Y_AXIS)) {
|
||||
brushBounds.y = wrap_value(brushBounds.y, sprite->height());
|
||||
extraCelBounds.y = brushBounds.y;
|
||||
if ((extraCelBounds.y < 0 && extraCelBounds.y2() > 0) ||
|
||||
(extraCelBounds.y < sprite->height() && extraCelBounds.y2() > sprite->height())) {
|
||||
extraCelBounds.y = 0;
|
||||
extraCelBounds.h = sprite->height();
|
||||
extraCelBoundsInCanvas.y = brushBounds.y;
|
||||
if ((extraCelBoundsInCanvas.y < 0 && extraCelBoundsInCanvas.y2() > 0) ||
|
||||
(extraCelBoundsInCanvas.y < sprite->height() && extraCelBoundsInCanvas.y2() > sprite->height())) {
|
||||
extraCelBoundsInCanvas.y = 0;
|
||||
extraCelBoundsInCanvas.h = sprite->height();
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect extraCelBoundsInCanvas;
|
||||
gfx::Rect extraCelBounds;
|
||||
if (site.tilemapMode() == TilemapMode::Tiles) {
|
||||
ASSERT(layer->isTilemap());
|
||||
extraCelBounds.setOrigin(site.grid().canvasToTile(extraCelBounds.origin()));
|
||||
extraCelBoundsInCanvas = site.grid().tileToCanvas(extraCelBounds);
|
||||
extraCelBounds = grid.canvasToTile(brushBounds);
|
||||
}
|
||||
else {
|
||||
extraCelBoundsInCanvas = extraCelBounds;
|
||||
extraCelBounds = extraCelBoundsInCanvas;
|
||||
}
|
||||
|
||||
// Create the extra cel to show the brush preview
|
||||
@ -287,9 +301,15 @@ void BrushPreview::show(const gfx::Point& screenPos)
|
||||
document->setExtraCel(m_extraCel);
|
||||
|
||||
Image* extraImage = m_extraCel->image();
|
||||
extraImage->setMaskColor(mask_index);
|
||||
clear_image(extraImage,
|
||||
(extraImage->pixelFormat() == IMAGE_INDEXED ? mask_index: 0));
|
||||
if (extraImage->pixelFormat() == IMAGE_TILEMAP) {
|
||||
extraImage->setMaskColor(tile_i_notile);
|
||||
clear_image(extraImage,tile_i_notile);
|
||||
}
|
||||
else {
|
||||
extraImage->setMaskColor(mask_index);
|
||||
clear_image(extraImage,
|
||||
(extraImage->pixelFormat() == IMAGE_INDEXED ? mask_index: 0));
|
||||
}
|
||||
|
||||
if (layer) {
|
||||
render::Render().renderLayer(
|
||||
|
@ -72,7 +72,8 @@ void DrawingState::initToolLoop(Editor* editor,
|
||||
m_toolLoop->getLayer(),
|
||||
m_toolLoop->getFrame(),
|
||||
m_toolLoop->getDstImage(),
|
||||
m_toolLoop->getCelOrigin(),
|
||||
m_toolLoop->getDstImage()->pixelFormat() == IMAGE_TILEMAP ?
|
||||
m_toolLoop->getGrid().origin() : m_toolLoop->getCelOrigin(),
|
||||
(m_toolLoop->getLayer() &&
|
||||
m_toolLoop->getLayer()->isImage() ?
|
||||
static_cast<LayerImage*>(m_toolLoop->getLayer())->blendMode():
|
||||
|
@ -351,7 +351,8 @@ void draw_image_into_new_tilemap_cel(
|
||||
newTilemap.reset(doc::Image::create(IMAGE_TILEMAP,
|
||||
tilemapBounds.w,
|
||||
tilemapBounds.h));
|
||||
newTilemap->clear(0); // <- This should not necessary
|
||||
newTilemap->setMaskColor(tile_i_notile);
|
||||
newTilemap->clear(tile_i_notile);
|
||||
}
|
||||
else {
|
||||
ASSERT(tilemapBounds.w == newTilemap->width());
|
||||
@ -444,7 +445,8 @@ void modify_tilemap_cel_region(
|
||||
newTilemapBounds.w,
|
||||
newTilemapBounds.h));
|
||||
|
||||
newTilemap->clear(0); // TODO find the tile with empty content?
|
||||
newTilemap->setMaskColor(tile_i_notile);
|
||||
newTilemap->clear(tile_i_notile); // TODO find the tile with empty content?
|
||||
newTilemap->copy(
|
||||
cel->image(),
|
||||
gfx::Clip(oldTilemapBounds.x-newTilemapBounds.x,
|
||||
@ -471,7 +473,7 @@ void modify_tilemap_cel_region(
|
||||
const doc::tile_index ti = doc::tile_geti(t);
|
||||
const doc::ImageRef existenTileImage = tileset->get(ti);
|
||||
|
||||
if (tilesetMode == TilesetMode::Auto)
|
||||
if (tilesetMode == TilesetMode::Auto && t != tile_i_notile)
|
||||
modifiedTileIndexes[ti] = true;
|
||||
|
||||
const gfx::Rect tileInCanvasRc(grid.tileToCanvas(tilePt), tileSize);
|
||||
@ -540,38 +542,40 @@ void modify_tilemap_cel_region(
|
||||
continue;
|
||||
|
||||
const doc::tile_t t = cel->image()->getPixel(tilePt.x, tilePt.y);
|
||||
const doc::tile_index ti = doc::tile_geti(t);
|
||||
const doc::ImageRef existenTileImage = tileset->get(ti);
|
||||
if (t != tile_i_notile) {
|
||||
const doc::tile_index ti = doc::tile_geti(t);
|
||||
const doc::ImageRef existenTileImage = tileset->get(ti);
|
||||
|
||||
const gfx::Rect tileInCanvasRc(grid.tileToCanvas(tilePt), tileSize);
|
||||
ImageRef tileImage(getTileImage(existenTileImage, tileInCanvasRc));
|
||||
if (grid.hasMask())
|
||||
mask_image(tileImage.get(), grid.mask().get());
|
||||
const gfx::Rect tileInCanvasRc(grid.tileToCanvas(tilePt), tileSize);
|
||||
ImageRef tileImage(getTileImage(existenTileImage, tileInCanvasRc));
|
||||
if (grid.hasMask())
|
||||
mask_image(tileImage.get(), grid.mask().get());
|
||||
|
||||
gfx::Region tileRgn(tileInCanvasRc);
|
||||
tileRgn.createIntersection(tileRgn, region);
|
||||
tileRgn.offset(-tileInCanvasRc.origin());
|
||||
gfx::Region tileRgn(tileInCanvasRc);
|
||||
tileRgn.createIntersection(tileRgn, region);
|
||||
tileRgn.offset(-tileInCanvasRc.origin());
|
||||
|
||||
ImageRef tileOrigImage = tileset->get(ti);
|
||||
ImageRef tileOrigImage = tileset->get(ti);
|
||||
|
||||
gfx::Region diffRgn;
|
||||
create_region_with_differences(tileOrigImage.get(),
|
||||
tileImage.get(),
|
||||
tileRgn.bounds(),
|
||||
diffRgn);
|
||||
gfx::Region diffRgn;
|
||||
create_region_with_differences(tileOrigImage.get(),
|
||||
tileImage.get(),
|
||||
tileRgn.bounds(),
|
||||
diffRgn);
|
||||
|
||||
// Keep only the modified region for this specific modification
|
||||
tileRgn &= diffRgn;
|
||||
// Keep only the modified region for this specific modification
|
||||
tileRgn &= diffRgn;
|
||||
|
||||
if (!tileRgn.isEmpty()) {
|
||||
Mod mod;
|
||||
mod.tileIndex = ti;
|
||||
mod.tileOrigImage = tileOrigImage;
|
||||
mod.tileImage = tileImage;
|
||||
mod.tileRgn = tileRgn;
|
||||
mods.push_back(mod);
|
||||
if (!tileRgn.isEmpty()) {
|
||||
Mod mod;
|
||||
mod.tileIndex = ti;
|
||||
mod.tileOrigImage = tileOrigImage;
|
||||
mod.tileImage = tileImage;
|
||||
mod.tileRgn = tileRgn;
|
||||
mods.push_back(mod);
|
||||
|
||||
modifiedTileIndexes[ti] = true;
|
||||
modifiedTileIndexes[ti] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,12 +659,14 @@ void remove_unused_tiles_from_tileset(
|
||||
for_each_pixel<TilemapTraits>(
|
||||
tilemapImage,
|
||||
[&unusedTiles, &n](const doc::tile_t t) {
|
||||
const doc::tile_index ti = doc::tile_geti(t);
|
||||
n = std::max<int>(n, ti+1);
|
||||
if (ti >= 0 &&
|
||||
ti < int(unusedTiles.size()) &&
|
||||
unusedTiles[ti]) {
|
||||
unusedTiles[ti] = false;
|
||||
if (t != tile_i_notile) {
|
||||
const doc::tile_index ti = doc::tile_geti(t);
|
||||
n = std::max<int>(n, ti+1);
|
||||
if (ti >= 0 &&
|
||||
ti < int(unusedTiles.size()) &&
|
||||
unusedTiles[ti]) {
|
||||
unusedTiles[ti] = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -129,13 +129,34 @@ ExpandCelCanvas::ExpandCelCanvas(
|
||||
}
|
||||
|
||||
if (m_tilemapMode == TilemapMode::Tiles) {
|
||||
m_bounds = site.grid().canvasToTile(m_bounds);
|
||||
// m_bounds represents the bounds of the m_srcImage/m_dstImage in tiles.
|
||||
gfx::Size srcSize = m_grid.canvasToTile(spriteBounds).size();
|
||||
m_bounds = gfx::Rect(m_grid.origin().x, m_grid.origin().y, srcSize.w, srcSize.h);
|
||||
// cel position will be according to the site.grid() (which is the grid origin,
|
||||
// alocated in the top-left corner of the canvas, it can be fit in the corner or
|
||||
// located a fraction outside of a tile.
|
||||
// m_grid.origin() represents that fraction in pixels units.
|
||||
//
|
||||
// grid.origin()
|
||||
// example = (-1, -1)
|
||||
// O---------|---------|----- <--- grid (example: tile size = 2x2)
|
||||
// | ____________________
|
||||
// | | <-- sprite canvas
|
||||
// - | .---------.
|
||||
// | | | |
|
||||
// | | | | <------- cel example= cel->position() = (1, 1)
|
||||
// - | '---------'
|
||||
// | |
|
||||
m_cel->setPosition(m_cel->position().x - m_grid.origin().x, m_cel->position().y - m_grid.origin().y);
|
||||
// following the example, cel->position() = (2, 2)
|
||||
// Here, we have a mixed units cel->bounds(): position in pixels, size in tiles.
|
||||
}
|
||||
else {
|
||||
// We have to adjust the cel position to match the m_dstImage
|
||||
// position (the new m_dstImage will be used in RenderEngine to
|
||||
// draw this cel).
|
||||
m_cel->setPosition(m_bounds.x, m_bounds.y);
|
||||
}
|
||||
|
||||
// We have to adjust the cel position to match the m_dstImage
|
||||
// position (the new m_dstImage will be used in RenderEngine to
|
||||
// draw this cel).
|
||||
m_cel->setPosition(m_bounds.x, m_bounds.y);
|
||||
|
||||
if (m_celCreated) {
|
||||
getDestCanvas();
|
||||
@ -144,6 +165,13 @@ ExpandCelCanvas::ExpandCelCanvas(
|
||||
if (m_layer && m_layer->isImage())
|
||||
static_cast<LayerImage*>(m_layer)->addCel(m_cel);
|
||||
}
|
||||
else if (m_layer->isTilemap() &&
|
||||
m_tilemapMode == TilemapMode::Tiles) {
|
||||
// Calling "getDestCanvas()" we create the m_dstImage
|
||||
getDestCanvas();
|
||||
m_dstImage->clear(tile_i_notile);
|
||||
m_cel->data()->setImage(m_dstImage, m_layer);
|
||||
}
|
||||
// If we are in a tilemap, we use m_dstImage to draw pixels (instead
|
||||
// of the tilemap image).
|
||||
else if (m_layer->isTilemap() &&
|
||||
@ -303,12 +331,25 @@ void ExpandCelCanvas::commit()
|
||||
m_bounds.origin()));
|
||||
}
|
||||
else {
|
||||
m_cmds->executeAndAdd(
|
||||
new cmd::PatchCel(
|
||||
m_cel,
|
||||
m_dstImage.get(),
|
||||
*regionToPatch,
|
||||
m_bounds.origin()));
|
||||
if (m_tilemapMode == TilemapMode::Tiles) {
|
||||
m_cel->data()->setImage(m_celImage, m_layer);
|
||||
gfx::Region regionInCanvas = m_grid.tileToCanvas(regionToPatch);
|
||||
regionToPatch = ®ionInCanvas;
|
||||
m_cmds->executeAndAdd(
|
||||
new cmd::PatchCel(
|
||||
m_cel,
|
||||
m_dstImage.get(),
|
||||
*regionToPatch,
|
||||
m_grid.origin()));
|
||||
}
|
||||
else {
|
||||
m_cmds->executeAndAdd(
|
||||
new cmd::PatchCel(
|
||||
m_cel,
|
||||
m_dstImage.get(),
|
||||
*regionToPatch,
|
||||
m_bounds.origin()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -349,13 +390,19 @@ Image* ExpandCelCanvas::getSourceCanvas()
|
||||
ASSERT((m_flags & NeedsSource) == NeedsSource);
|
||||
|
||||
if (!m_srcImage) {
|
||||
m_srcImage.reset(
|
||||
Image::create(m_tilemapMode == TilemapMode::Tiles ? IMAGE_TILEMAP:
|
||||
m_sprite->pixelFormat(),
|
||||
if (m_tilemapMode == TilemapMode::Tiles) {
|
||||
m_srcImage.reset(Image::create(IMAGE_TILEMAP,
|
||||
m_bounds.w, m_bounds.h, src_buffer));
|
||||
m_srcImage->setMaskColor(tile_i_notile);
|
||||
m_srcImage->clear(tile_i_notile);
|
||||
}
|
||||
else {
|
||||
m_srcImage.reset(
|
||||
Image::create(m_sprite->pixelFormat(),
|
||||
m_bounds.w, m_bounds.h, src_buffer));
|
||||
|
||||
m_srcImage->setMaskColor(m_sprite->transparentColor());
|
||||
m_srcImage->clear(m_sprite->transparentColor());
|
||||
m_srcImage->setMaskColor(m_sprite->transparentColor());
|
||||
m_srcImage->clear(m_sprite->transparentColor());
|
||||
}
|
||||
}
|
||||
return m_srcImage.get();
|
||||
}
|
||||
@ -363,12 +410,16 @@ Image* ExpandCelCanvas::getSourceCanvas()
|
||||
Image* ExpandCelCanvas::getDestCanvas()
|
||||
{
|
||||
if (!m_dstImage) {
|
||||
m_dstImage.reset(
|
||||
Image::create(m_tilemapMode == TilemapMode::Tiles ? IMAGE_TILEMAP:
|
||||
m_sprite->pixelFormat(),
|
||||
m_bounds.w, m_bounds.h, dst_buffer));
|
||||
|
||||
m_dstImage->setMaskColor(m_sprite->transparentColor());
|
||||
if (m_tilemapMode == TilemapMode::Tiles) {
|
||||
m_dstImage.reset(Image::create(IMAGE_TILEMAP,
|
||||
m_bounds.w, m_bounds.h, dst_buffer));
|
||||
m_dstImage->setMaskColor(tile_i_notile);
|
||||
}
|
||||
else {
|
||||
m_dstImage.reset(Image::create(m_sprite->pixelFormat(),
|
||||
m_bounds.w, m_bounds.h, dst_buffer));
|
||||
m_dstImage->setMaskColor(m_sprite->transparentColor());
|
||||
}
|
||||
}
|
||||
return m_dstImage.get();
|
||||
}
|
||||
@ -380,7 +431,9 @@ void ExpandCelCanvas::validateSourceCanvas(const gfx::Region& rgn)
|
||||
getSourceCanvas();
|
||||
|
||||
gfx::Region rgnToValidate;
|
||||
gfx::Point celImagePos;
|
||||
if (m_tilemapMode == TilemapMode::Tiles) {
|
||||
celImagePos = m_grid.canvasToTile(m_cel->position());
|
||||
for (const auto& rc : rgn)
|
||||
rgnToValidate |= gfx::Region(m_grid.canvasToTile(rc));
|
||||
}
|
||||
@ -389,16 +442,21 @@ void ExpandCelCanvas::validateSourceCanvas(const gfx::Region& rgn)
|
||||
}
|
||||
EXP_TRACE(" ->", rgnToValidate.bounds());
|
||||
|
||||
rgnToValidate.offset(-m_bounds.origin());
|
||||
if (m_tilemapMode != TilemapMode::Tiles)
|
||||
rgnToValidate.offset(-m_bounds.origin());
|
||||
rgnToValidate.createSubtraction(rgnToValidate, m_validSrcRegion);
|
||||
rgnToValidate.createIntersection(rgnToValidate, gfx::Region(m_srcImage->bounds()));
|
||||
|
||||
if (m_validSrcRegion.bounds() == gfx::Rect(1, 1, 6, 6))
|
||||
int aaa = 0;
|
||||
|
||||
if (m_celImage) {
|
||||
gfx::Region rgnToClear;
|
||||
rgnToClear.createSubtraction(
|
||||
rgnToValidate,
|
||||
gfx::Region(m_celImage->bounds()
|
||||
.offset(m_origCelPos)
|
||||
.offset(m_tilemapMode == TilemapMode::Tiles ?
|
||||
celImagePos + m_bounds.origin() : m_origCelPos)
|
||||
.offset(-m_bounds.origin())));
|
||||
for (const auto& rc : rgnToClear)
|
||||
fill_rect(m_srcImage.get(), rc, m_srcImage->maskColor());
|
||||
@ -424,6 +482,18 @@ void ExpandCelCanvas::validateSourceCanvas(const gfx::Region& rgn)
|
||||
255, BlendMode::NORMAL);
|
||||
}
|
||||
}
|
||||
else if (m_celImage->pixelFormat() == IMAGE_TILEMAP &&
|
||||
m_srcImage->pixelFormat() == IMAGE_TILEMAP) {
|
||||
ASSERT(m_tilemapMode == TilemapMode::Tiles);
|
||||
|
||||
// We can copy the cel image directly
|
||||
for (const auto& rc : rgnToValidate)
|
||||
m_srcImage->copy(
|
||||
m_celImage.get(),
|
||||
gfx::Clip(rc.x, rc.y,
|
||||
rc.x - celImagePos.x,
|
||||
rc.y - celImagePos.y, rc.w, rc.h));
|
||||
}
|
||||
else {
|
||||
ASSERT(m_celImage->pixelFormat() != IMAGE_TILEMAP ||
|
||||
m_tilemapMode == TilemapMode::Tiles);
|
||||
@ -475,7 +545,8 @@ void ExpandCelCanvas::validateDestCanvas(const gfx::Region& rgn)
|
||||
}
|
||||
EXP_TRACE(" ->", rgnToValidate.bounds());
|
||||
|
||||
rgnToValidate.offset(-m_bounds.origin());
|
||||
if (m_tilemapMode != TilemapMode::Tiles)
|
||||
rgnToValidate.offset(-m_bounds.origin());
|
||||
rgnToValidate.createSubtraction(rgnToValidate, m_validDstRegion);
|
||||
rgnToValidate.createIntersection(rgnToValidate, gfx::Region(m_dstImage->bounds()));
|
||||
|
||||
|
@ -782,6 +782,8 @@ doc::Cel* AsepriteDecoder::readCelChunk(doc::Sprite* sprite,
|
||||
|
||||
if (w > 0 && h > 0) {
|
||||
doc::ImageRef image(doc::Image::create(doc::IMAGE_TILEMAP, w, h));
|
||||
image->setMaskColor(doc::tile_i_notile);
|
||||
image->clear(doc::tile_i_notile);
|
||||
read_compressed_image(f(), delegate(), image.get(), header, chunk_end);
|
||||
cel.reset(new doc::Cel(frame, image));
|
||||
cel->setPosition(x, y);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -15,6 +15,7 @@
|
||||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/tile.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
@ -149,7 +150,8 @@ void Cel::fixupImage()
|
||||
{
|
||||
// Change the mask color to the sprite mask color
|
||||
if (m_layer && image()) {
|
||||
image()->setMaskColor(m_layer->sprite()->transparentColor());
|
||||
image()->setMaskColor((image()->pixelFormat() == IMAGE_TILEMAP) ?
|
||||
tile_i_notile : m_layer->sprite()->transparentColor());
|
||||
ASSERT(m_data);
|
||||
m_data->adjustBounds(m_layer);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2019-2020 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -52,6 +52,15 @@ gfx::Rect Grid::tileToCanvas(const gfx::Rect& tileBounds) const
|
||||
return gfx::Rect(pt1, pt2);
|
||||
}
|
||||
|
||||
gfx::Region Grid::tileToCanvas(gfx::Region* tileRgn)
|
||||
{
|
||||
gfx::Region canvasRgn;
|
||||
for (const gfx::Rect& rc : *tileRgn) {
|
||||
canvasRgn |= gfx::Region(tileToCanvas(rc));
|
||||
}
|
||||
return canvasRgn;
|
||||
}
|
||||
|
||||
gfx::Point Grid::canvasToTile(const gfx::Point& canvasPoint) const
|
||||
{
|
||||
ASSERT(m_tileSize.w > 0);
|
||||
@ -107,6 +116,16 @@ gfx::Rect Grid::canvasToTile(const gfx::Rect& canvasBounds) const
|
||||
pt2.y - pt1.y + 1));
|
||||
}
|
||||
|
||||
gfx::Region Grid::canvasToTile(const gfx::Region& canvasRgn)
|
||||
{
|
||||
gfx::Region tilesRgn;
|
||||
for (const gfx::Rect& rc : canvasRgn) {
|
||||
tilesRgn |= gfx::Region(canvasToTile(rc));
|
||||
}
|
||||
return tilesRgn;
|
||||
|
||||
}
|
||||
|
||||
gfx::Size Grid::tilemapSizeToCanvas(const gfx::Size& tilemapSize) const
|
||||
{
|
||||
gfx::Point pt = tileToCanvas(gfx::Point(tilemapSize.w-1,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2019-2020 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -47,10 +47,12 @@ namespace doc {
|
||||
// Converts a tile position into a canvas position
|
||||
gfx::Point tileToCanvas(const gfx::Point& tile) const;
|
||||
gfx::Rect tileToCanvas(const gfx::Rect& tileBounds) const;
|
||||
gfx::Region tileToCanvas(gfx::Region* tileRgn);
|
||||
|
||||
// Converts a canvas position/rectangle into a tile position
|
||||
gfx::Point canvasToTile(const gfx::Point& canvasPoint) const;
|
||||
gfx::Rect canvasToTile(const gfx::Rect& canvasBounds) const;
|
||||
gfx::Region canvasToTile(const gfx::Region& canvasRgn);
|
||||
|
||||
gfx::Size tilemapSizeToCanvas(const gfx::Size& tilemapSize) const;
|
||||
gfx::Rect tileBoundsInCanvas(const gfx::Point& tile) const;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2018-2019 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -17,6 +17,7 @@
|
||||
#include "doc/palette.h"
|
||||
#include "doc/remap.h"
|
||||
#include "doc/rgbmap.h"
|
||||
#include "doc/tile.h"
|
||||
#include "gfx/region.h"
|
||||
|
||||
#include <stdexcept>
|
||||
@ -426,8 +427,12 @@ void remap_image(Image* image, const Remap& remap)
|
||||
case IMAGE_TILEMAP:
|
||||
transform_image<TilemapTraits>(
|
||||
image, [&remap](color_t c) -> color_t {
|
||||
ASSERT(remap[c] != Remap::kNoMap);
|
||||
return remap[c];
|
||||
if (c == tile_i_notile)
|
||||
return tile_i_notile;
|
||||
else {
|
||||
ASSERT(remap[c] != Remap::kNoMap);
|
||||
return remap[c];
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -1285,18 +1285,20 @@ void Render::renderCel(
|
||||
continue;
|
||||
|
||||
const tile_t t = cel_image->getPixel(u, v);
|
||||
const tile_index i = tile_geti(t);
|
||||
if (t != tile_i_notile) {
|
||||
const tile_index i = tile_geti(t);
|
||||
|
||||
if (dst_image->pixelFormat() == IMAGE_TILEMAP) {
|
||||
put_pixel(dst_image, u-area.dst.x, v-area.dst.y, t);
|
||||
}
|
||||
else {
|
||||
const ImageRef tile_image = tileset->get(i);
|
||||
if (!tile_image)
|
||||
continue;
|
||||
if (dst_image->pixelFormat() == IMAGE_TILEMAP) {
|
||||
put_pixel(dst_image, u-area.dst.x, v-area.dst.y, t);
|
||||
}
|
||||
else {
|
||||
const ImageRef tile_image = tileset->get(i);
|
||||
if (!tile_image)
|
||||
continue;
|
||||
|
||||
renderImage(dst_image, tile_image.get(), pal, tileBoundsOnCanvas,
|
||||
area, compositeImage, opacity, blendMode);
|
||||
renderImage(dst_image, tile_image.get(), pal, tileBoundsOnCanvas,
|
||||
area, compositeImage, opacity, blendMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user