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:
Gaspar Capello 2020-08-06 10:39:40 -03:00 committed by David Capello
parent 2ffac6803c
commit a195487fc0
16 changed files with 295 additions and 122 deletions

View File

@ -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();

View File

@ -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));

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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(

View File

@ -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():

View File

@ -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;
}
}
});
}

View File

@ -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 = &regionInCanvas;
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()));

View File

@ -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);

View File

@ -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);
}

View File

@ -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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}
}
}
}