More usage of Tile/Metatile size constants

This commit is contained in:
GriffinR 2025-07-14 14:20:39 -04:00
parent 38e2772213
commit 5fa5638277
35 changed files with 274 additions and 257 deletions

View File

@ -66,57 +66,7 @@ class PorymapConfig: public KeyValueConfigBase
{
public:
PorymapConfig();
virtual void reset() override {
setRoot(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
this->recentProjects.clear();
this->projectManuallyClosed = false;
this->reopenOnLaunch = true;
this->mapListTab = 0;
this->mapListEditGroupsEnabled = false;
this->mapListHideEmptyEnabled.clear();
this->prettyCursors = true;
this->mirrorConnectingMaps = true;
this->showDiveEmergeMaps = false;
this->diveEmergeMapOpacity = 30;
this->diveMapOpacity = 15;
this->emergeMapOpacity = 15;
this->collisionOpacity = 50;
this->collisionZoom = 30;
this->metatilesZoom = 30;
this->tilesetEditorMetatilesZoom = 30;
this->tilesetEditorTilesZoom = 30;
this->showPlayerView = false;
this->showCursorTile = true;
this->showBorder = true;
this->showGrid = false;
this->showTilesetEditorMetatileGrid = false;
this->showTilesetEditorLayerGrid = true;
this->showTilesetEditorDivider = false;
this->showTilesetEditorRawAttributes = false;
this->monitorFiles = true;
this->tilesetCheckerboardFill = true;
this->newMapHeaderSectionExpanded = false;
this->theme = "default";
this->wildMonChartTheme = "";
this->textEditorOpenFolder = "";
this->textEditorGotoLine = "";
this->paletteEditorBitDepth = 24;
this->projectSettingsTab = 0;
this->loadAllEventScripts = false;
this->warpBehaviorWarningDisabled = false;
this->eventDeleteWarningDisabled = false;
this->eventOverlayEnabled = false;
this->checkForUpdates = true;
this->lastUpdateCheckTime = QDateTime();
this->lastUpdateCheckVersion = porymapVersion;
this->rateLimitTimes.clear();
this->eventSelectionShapeMode = QGraphicsPixmapItem::MaskShape;
this->shownInGameReloadMessage = false;
this->gridSettings = GridSettings();
this->statusBarLogTypes = { LogType::LOG_ERROR, LogType::LOG_WARN };
this->applicationFont = QFont();
this->mapListFont = PorymapConfig::defaultMapListFont();
}
virtual void reset() override;
void addRecentProject(QString project);
void setRecentProjects(QStringList projects);
QString getRecentProject();

View File

@ -51,10 +51,12 @@ public:
void setLayoutId(const QString &layoutId) { m_layoutId = layoutId; }
QString layoutId() const { return layout() ? layout()->id : m_layoutId; }
int getWidth() const;
int getHeight() const;
int getBorderWidth() const;
int getBorderHeight() const;
int getWidth() const { return m_layout ? m_layout->getWidth() : 0; }
int getHeight() const { return m_layout ? m_layout->getHeight() : 0; }
int getBorderWidth() const { return m_layout ? m_layout->getBorderWidth() : 0; }
int getBorderHeight() const { return m_layout ? m_layout->getBorderHeight() : 0; }
int pixelWidth() const { return m_layout ? m_layout->pixelWidth() : 0; }
int pixelHeight() const { return m_layout ? m_layout->pixelHeight() : 0; }
void setHeader(const MapHeader &header) { *m_header = header; }
MapHeader* header() const { return m_header; }

View File

@ -42,7 +42,7 @@ public:
MapConnection* createMirror();
QPixmap render() const;
QPoint relativePos(bool clipped = false) const;
QPoint relativePixelPos(bool clipped = false) const;
static QPointer<Project> project;
static const QMap<QString, QString> oppositeDirections;

View File

@ -32,6 +32,9 @@ public:
int height;
int border_width;
int border_height;
int pixelWidth() const { return this->width * Metatile::pixelWidth(); }
int pixelHeight() const { return this->height * Metatile::pixelHeight(); }
QSize pixelSize() const { return QSize(pixelWidth(), pixelHeight()); }
QString border_path;
QString blockdata_path;
@ -153,7 +156,7 @@ public:
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void magicFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
QPixmap render(bool ignoreCache = false, Layout *fromLayout = nullptr, QRect bounds = QRect(0, 0, -1, -1));
QPixmap render(bool ignoreCache = false, Layout *fromLayout = nullptr, const QRect &bounds = QRect(0, 0, -1, -1));
QPixmap renderCollision(bool ignoreCache);
// QPixmap renderConnection(MapConnection, Layout *);
QPixmap renderBorder(bool ignoreCache = false);

View File

@ -64,12 +64,12 @@ public:
static QString getMetatileIdStrings(const QList<uint16_t> metatileIds);
static QString getLayerName(int layerNum);
static int tileWidth() { return 2; }
static int tileHeight() { return 2; }
static int tilesPerLayer() { return Metatile::tileWidth() * Metatile::tileHeight(); }
static int pixelWidth() { return Metatile::tileWidth() * Tile::pixelWidth(); }
static int pixelHeight() { return Metatile::tileHeight() * Tile::pixelHeight(); }
static QSize pixelSize() { return QSize(pixelWidth(), pixelHeight()); }
static constexpr int tileWidth() { return 2; }
static constexpr int tileHeight() { return 2; }
static constexpr int tilesPerLayer() { return Metatile::tileWidth() * Metatile::tileHeight(); }
static constexpr int pixelWidth() { return Metatile::tileWidth() * Tile::pixelWidth(); }
static constexpr int pixelHeight() { return Metatile::tileHeight() * Tile::pixelHeight(); }
static constexpr QSize pixelSize() { return QSize(pixelWidth(), pixelHeight()); }
inline bool operator==(const Metatile &other) {
return this->tiles == other.tiles && this->attributes == other.attributes;

View File

@ -26,9 +26,9 @@ public:
static const uint16_t maxValue;
static int pixelWidth() { return 8; }
static int pixelHeight() { return 8; }
static QSize pixelSize() { return QSize(Tile::pixelWidth(), Tile::pixelHeight()); }
static constexpr int pixelWidth() { return 8; }
static constexpr int pixelHeight() { return 8; }
static constexpr QSize pixelSize() { return QSize(Tile::pixelWidth(), Tile::pixelHeight()); }
};
inline bool operator==(const Tile &a, const Tile &b) {

View File

@ -251,6 +251,7 @@ public:
static QString getDynamicMapDefineName();
static QString getDynamicMapName();
static QString getEmptySpeciesName();
static QMargins getPixelViewDistance();
static QMargins getMetatileViewDistance();
static int getNumTilesPrimary() { return num_tiles_primary; }
static int getNumTilesTotal() { return num_tiles_total; }

View File

@ -2,6 +2,7 @@
#define CONNECTIONPIXMAPITEM_H
#include "mapconnection.h"
#include "metatile.h"
#include <QGraphicsPixmapItem>
#include <QPainter>
#include <QPointer>
@ -31,8 +32,8 @@ private:
bool selected = false;
unsigned actionId = 0;
static const int mWidth = 16;
static const int mHeight = 16;
static const int mWidth = Metatile::pixelWidth();
static const int mHeight = Metatile::pixelHeight();
void updatePos();
void updateOrigin();

View File

@ -3,6 +3,7 @@
#include <QGraphicsObject>
#include <QLine>
#include "metatile.h"
class MapRuler : public QGraphicsObject, private QLine
@ -63,8 +64,8 @@ private:
QPoint snapToWithinBounds(QPoint pos) const;
void updateGeometry();
void updateStatus(Qt::Corner corner);
int pixWidth() const { return width() * 16; }
int pixHeight() const { return height() * 16; }
int pixWidth() const { return width() * Metatile::pixelWidth(); }
int pixHeight() const { return height() * Metatile::pixelHeight(); }
};
#endif // MAPRULER_H

View File

@ -31,7 +31,7 @@ struct MetatileSelection
class MetatileSelector: public SelectablePixmapItem {
Q_OBJECT
public:
MetatileSelector(int numMetatilesWide, Layout *layout): SelectablePixmapItem(16, 16) {
MetatileSelector(int numMetatilesWide, Layout *layout): SelectablePixmapItem(Metatile::pixelWidth(), Metatile::pixelHeight()) {
this->externalSelection = false;
this->prefabSelection = false;
this->numMetatilesWide = numMetatilesWide;

View File

@ -10,7 +10,7 @@
class MovableRect : public QGraphicsRectItem
{
public:
MovableRect(const QRectF &rect, const QRgb &color);
MovableRect(const QRectF &rect, const QSize &cellSize, const QRgb &color);
QRectF boundingRect() const override {
qreal penWidth = 4;
return QRectF(-penWidth,
@ -31,6 +31,7 @@ public:
protected:
QRectF baseRect;
QSize cellSize;
QRgb color;
void updateVisibility();
@ -43,7 +44,7 @@ class ResizableRect : public QObject, public MovableRect
{
Q_OBJECT
public:
ResizableRect(QObject *parent, int width, int height, QRgb color);
ResizableRect(QObject *parent, const QSize &cellSize, const QSize &size, const QRgb &color);
QRectF boundingRect() const override {
return QRectF(this->rect() + QMargins(lineWidth, lineWidth, lineWidth, lineWidth));

View File

@ -45,10 +45,10 @@ private:
/// PixmapItem subclass which allows for creating a boundary which determine whether
/// the pixmap paints normally or with a black tint.
/// This item is movable and snaps on a 16x16 grid.
/// This item is movable and snaps on a 'cellSize' grid.
class BoundedPixmapItem : public QGraphicsPixmapItem {
public:
BoundedPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent = nullptr);
BoundedPixmapItem(const QPixmap &pixmap, const QSize &cellSize, QGraphicsItem *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override;
void setBoundary(ResizableRect *rect) { this->boundary = rect; }
@ -59,6 +59,7 @@ protected:
private:
ResizableRect *boundary = nullptr;
QPointF clickedPos = QPointF();
QSize cellSize;
};

View File

@ -7,13 +7,18 @@
class SelectablePixmapItem : public QObject, public QGraphicsPixmapItem {
Q_OBJECT
public:
SelectablePixmapItem(int cellWidth, int cellHeight): SelectablePixmapItem(cellWidth, cellHeight, INT_MAX, INT_MAX) {}
SelectablePixmapItem(int cellWidth, int cellHeight, int maxSelectionWidth, int maxSelectionHeight) {
this->cellWidth = cellWidth;
this->cellHeight = cellHeight;
this->maxSelectionWidth = maxSelectionWidth;
this->maxSelectionHeight = maxSelectionHeight;
}
SelectablePixmapItem(const QSize &size, const QSize &maxSelectionSize = QSize(INT_MAX, INT_MAX))
: SelectablePixmapItem(size.width(), size.height(), maxSelectionSize.width(), maxSelectionSize.height()) {}
SelectablePixmapItem(int cellWidth, int cellHeight, int maxSelectionWidth = INT_MAX, int maxSelectionHeight = INT_MAX)
: cellWidth(cellWidth),
cellHeight(cellHeight),
maxSelectionWidth(maxSelectionWidth),
maxSelectionHeight(maxSelectionHeight),
selectionInitialX(0),
selectionInitialY(0),
selectionOffsetX(0),
selectionOffsetY(0)
{}
virtual QPoint getSelectionDimensions();
virtual void draw() = 0;

View File

@ -8,7 +8,7 @@ class TilesetEditorTileSelector: public SelectablePixmapItem {
Q_OBJECT
public:
TilesetEditorTileSelector(Tileset *primaryTileset, Tileset *secondaryTileset, int numLayers)
: SelectablePixmapItem(16, 16, numLayers * 2, 2) {
: SelectablePixmapItem(16, 16, numLayers * Metatile::tileWidth(), Metatile::tileHeight()) {
this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset;
this->numTilesWide = 16;

View File

@ -4,6 +4,7 @@
#include "map.h"
#include "validator.h"
#include "utility.h"
#include "metatile.h"
#include <QDir>
#include <QFile>
#include <QFormLayout>
@ -315,6 +316,60 @@ PorymapConfig::PorymapConfig() : KeyValueConfigBase(QStringLiteral("porymap.cfg"
reset();
}
void PorymapConfig::reset() {
setRoot(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
this->recentProjects.clear();
this->projectManuallyClosed = false;
this->reopenOnLaunch = true;
this->mapListTab = 0;
this->mapListEditGroupsEnabled = false;
this->mapListHideEmptyEnabled.clear();
this->prettyCursors = true;
this->mirrorConnectingMaps = true;
this->showDiveEmergeMaps = false;
this->diveEmergeMapOpacity = 30;
this->diveMapOpacity = 15;
this->emergeMapOpacity = 15;
this->collisionOpacity = 50;
this->collisionZoom = 30;
this->metatilesZoom = 30;
this->tilesetEditorMetatilesZoom = 30;
this->tilesetEditorTilesZoom = 30;
this->showPlayerView = false;
this->showCursorTile = true;
this->showBorder = true;
this->showGrid = false;
this->showTilesetEditorMetatileGrid = false;
this->showTilesetEditorLayerGrid = true;
this->showTilesetEditorDivider = false;
this->showTilesetEditorRawAttributes = false;
this->monitorFiles = true;
this->tilesetCheckerboardFill = true;
this->newMapHeaderSectionExpanded = false;
this->theme = "default";
this->wildMonChartTheme = "";
this->textEditorOpenFolder = "";
this->textEditorGotoLine = "";
this->paletteEditorBitDepth = 24;
this->projectSettingsTab = 0;
this->loadAllEventScripts = false;
this->warpBehaviorWarningDisabled = false;
this->eventDeleteWarningDisabled = false;
this->eventOverlayEnabled = false;
this->checkForUpdates = true;
this->lastUpdateCheckTime = QDateTime();
this->lastUpdateCheckVersion = porymapVersion;
this->rateLimitTimes.clear();
this->eventSelectionShapeMode = QGraphicsPixmapItem::MaskShape;
this->shownInGameReloadMessage = false;
this->gridSettings = GridSettings();
this->gridSettings.width = Metatile::pixelWidth();
this->gridSettings.height = Metatile::pixelHeight();
this->statusBarLogTypes = { LogType::LOG_ERROR, LogType::LOG_WARN };
this->applicationFont = QFont();
this->mapListFont = PorymapConfig::defaultMapListFont();
}
void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
if (key == "recent_project") {
this->recentProjects = value.split(",", Qt::SkipEmptyParts);
@ -1186,7 +1241,7 @@ int ProjectConfig::getNumLayersInMetatile() {
}
int ProjectConfig::getNumTilesInMetatile() {
return this->tripleLayerMetatilesEnabled ? 12 : 8;
return getNumLayersInMetatile() * Metatile::tilesPerLayer();
}
void ProjectConfig::setEventIconPath(Event::Group group, const QString &path) {

View File

@ -62,44 +62,28 @@ QString Map::mapConstantFromName(const QString &name) {
return projectConfig.getIdentifier(ProjectIdentifier::define_map_prefix) + Util::toDefineCase(name);
}
int Map::getWidth() const {
return m_layout ? m_layout->getWidth() : 0;
}
int Map::getHeight() const {
return m_layout ? m_layout->getHeight() : 0;
}
int Map::getBorderWidth() const {
return m_layout ? m_layout->getBorderWidth() : 0;
}
int Map::getBorderHeight() const {
return m_layout ? m_layout->getBorderHeight() : 0;
}
// Get the portion of the map that can be rendered when rendered as a map connection.
// Cardinal connections render the nearest segment of their map and within the bounds of the border draw distance,
// Dive/Emerge connections are rendered normally within the bounds of their parent map.
QRect Map::getConnectionRect(const QString &direction, Layout * fromLayout) const {
int x = 0, y = 0;
int w = getWidth(), h = getHeight();
int w = pixelWidth(), h = pixelHeight();
QMargins viewDistance = Project::getMetatileViewDistance();
QMargins viewDistance = Project::getPixelViewDistance();
if (direction == "up") {
h = qMin(h, viewDistance.top());
y = getHeight() - h;
y = pixelHeight() - h;
} else if (direction == "down") {
h = qMin(h, viewDistance.bottom());
} else if (direction == "left") {
w = qMin(w, viewDistance.left());
x = getWidth() - w;
x = pixelWidth() - w;
} else if (direction == "right") {
w = qMin(w, viewDistance.right());
} else if (MapConnection::isDiving(direction)) {
if (fromLayout) {
w = qMin(w, fromLayout->getWidth());
h = qMin(h, fromLayout->getHeight());
w = qMin(w, fromLayout->pixelWidth());
h = qMin(h, fromLayout->pixelHeight());
}
} else {
// Unknown direction
@ -122,7 +106,7 @@ QPixmap Map::renderConnection(const QString &direction, Layout * fromLayout) {
fromLayout = nullptr;
QPixmap connectionPixmap = m_layout->render(true, fromLayout, bounds);
return connectionPixmap.copy(bounds.x() * 16, bounds.y() * 16, bounds.width() * 16, bounds.height() * 16);
return connectionPixmap.copy(bounds);
}
void Map::openScript(const QString &label) {

View File

@ -72,20 +72,20 @@ QPixmap MapConnection::render() const {
// For right/down connections this is offset by the dimensions of the parent map.
// For left/up connections this is offset by the dimensions of the target map.
// If 'clipped' is true, only the rendered dimensions of the target map will be used, rather than its full dimensions.
QPoint MapConnection::relativePos(bool clipped) const {
QPoint MapConnection::relativePixelPos(bool clipped) const {
int x = 0, y = 0;
if (m_direction == "right") {
if (m_parentMap) x = m_parentMap->getWidth();
if (m_parentMap) x = m_parentMap->pixelWidth();
y = m_offset;
} else if (m_direction == "down") {
x = m_offset;
if (m_parentMap) y = m_parentMap->getHeight();
if (m_parentMap) y = m_parentMap->pixelHeight();
} else if (m_direction == "left") {
if (targetMap()) x = !clipped ? -targetMap()->getWidth() : -targetMap()->getConnectionRect(m_direction).width();
if (targetMap()) x = !clipped ? -targetMap()->pixelWidth() : -targetMap()->getConnectionRect(m_direction).width();
y = m_offset;
} else if (m_direction == "up") {
x = m_offset;
if (targetMap()) y = !clipped ? -targetMap()->getHeight() : -targetMap()->getConnectionRect(m_direction).height();
if (targetMap()) y = !clipped ? -targetMap()->pixelHeight() : -targetMap()->getConnectionRect(m_direction).height();
}
return QPoint(x, y);
}

View File

@ -92,12 +92,11 @@ QMargins Layout::getBorderMargins() const {
return distance;
}
// Get a rectangle that represents (in pixels) the layout's map area and the visible area of its border.
// At maximum, this is equal to the map size plus the border margins.
// If the border is large (and so beyond player the view) it may be smaller than that.
// Get a rectangle that represents (in pixels) the layout's map area + the distance the player can see.
// Note that this may be smaller than the map area + the size of the border for layouts with large border dimensions.
QRect Layout::getVisibleRect() const {
QRect area = QRect(0, 0, this->width * 16, this->height * 16);
return area += (Project::getMetatileViewDistance() * 16);
QRect area = QRect(0, 0, this->pixelWidth(), this->pixelHeight());
return area += Project::getPixelViewDistance();
}
bool Layout::getBlock(int x, int y, Block *out) {
@ -344,15 +343,13 @@ void Layout::magicFillCollisionElevation(int initialX, int initialY, uint16_t co
}
}
QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, const QRect &bounds) {
bool changed_any = false;
int width_ = getWidth();
int height_ = getHeight();
if (this->image.isNull() || this->image.width() != width_ * 16 || this->image.height() != height_ * 16) {
this->image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
if (this->image.isNull() || this->image.width() != pixelWidth() || this->image.height() != pixelHeight()) {
this->image = QImage(pixelWidth(), pixelHeight(), QImage::Format_RGBA8888);
changed_any = true;
}
if (this->blockdata.isEmpty() || !width_ || !height_) {
if (this->blockdata.isEmpty() || this->width == 0 || this->height == 0) {
this->pixmap = this->pixmap.fromImage(this->image);
return this->pixmap;
}
@ -368,9 +365,9 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
if (!ignoreCache && !layoutBlockChanged(i, this->blockdata, this->cached_blockdata)) {
continue;
}
int map_y = width_ ? i / width_ : 0;
int map_x = width_ ? i % width_ : 0;
if (bounds.isValid() && !bounds.contains(map_x, map_y)) {
int x = this->width ? ((i % this->width) * Metatile::pixelWidth()) : 0;
int y = this->width ? ((i / this->width) * Metatile::pixelHeight()) : 0;
if (bounds.isValid() && !bounds.contains(x, y)) {
continue;
}
@ -388,9 +385,7 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
);
imageCache.insert(metatileId, metatileImage);
}
QPoint metatileOrigin = QPoint(map_x * 16, map_y * 16);
painter.drawImage(metatileOrigin, metatileImage);
painter.drawImage(x, y, metatileImage);
changed_any = true;
}
painter.end();
@ -404,13 +399,11 @@ QPixmap Layout::render(bool ignoreCache, Layout *fromLayout, QRect bounds) {
QPixmap Layout::renderCollision(bool ignoreCache) {
bool changed_any = false;
int width_ = getWidth();
int height_ = getHeight();
if (collision_image.isNull() || collision_image.width() != width_ * 16 || collision_image.height() != height_ * 16) {
collision_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
if (collision_image.isNull() || collision_image.width() != pixelWidth() || collision_image.height() != pixelHeight()) {
collision_image = QImage(pixelWidth(), pixelHeight(), QImage::Format_RGBA8888);
changed_any = true;
}
if (this->blockdata.isEmpty() || !width_ || !height_) {
if (this->blockdata.isEmpty() || this->width == 0 || this->height == 0) {
collision_pixmap = collision_pixmap.fromImage(collision_image);
return collision_pixmap;
}
@ -422,10 +415,9 @@ QPixmap Layout::renderCollision(bool ignoreCache) {
changed_any = true;
Block block = this->blockdata.at(i);
QImage collision_metatile_image = getCollisionMetatileImage(block);
int map_y = width_ ? i / width_ : 0;
int map_x = width_ ? i % width_ : 0;
QPoint metatile_origin = QPoint(map_x * 16, map_y * 16);
painter.drawImage(metatile_origin, collision_metatile_image);
int x = this->width ? ((i % this->width) * Metatile::pixelWidth()) : 0;
int y = this->width ? ((i / this->width) * Metatile::pixelHeight()) : 0;
painter.drawImage(x, y, collision_metatile_image);
}
painter.end();
cacheCollision();
@ -437,14 +429,14 @@ QPixmap Layout::renderCollision(bool ignoreCache) {
QPixmap Layout::renderBorder(bool ignoreCache) {
bool changed_any = false, border_resized = false;
int width_ = getBorderWidth();
int height_ = getBorderHeight();
int pixelWidth = this->border_width * Metatile::pixelWidth();
int pixelHeight = this->border_height * Metatile::pixelHeight();
if (this->border_image.isNull()) {
this->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
this->border_image = QImage(pixelWidth, pixelHeight, QImage::Format_RGBA8888);
changed_any = true;
}
if (this->border_image.width() != width_ * 16 || this->border_image.height() != height_ * 16) {
this->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
if (this->border_image.width() != pixelWidth || this->border_image.height() != pixelHeight) {
this->border_image = QImage(pixelWidth, pixelHeight, QImage::Format_RGBA8888);
border_resized = true;
}
if (this->border.isEmpty()) {
@ -461,9 +453,9 @@ QPixmap Layout::renderBorder(bool ignoreCache) {
Block block = this->border.at(i);
uint16_t metatileId = block.metatileId();
QImage metatile_image = getMetatileImage(metatileId, this);
int map_y = width_ ? i / width_ : 0;
int map_x = width_ ? i % width_ : 0;
painter.drawImage(QPoint(map_x * 16, map_y * 16), metatile_image);
int x = this->border_width ? ((i % this->border_width) * Metatile::pixelWidth()) : 0;
int y = this->border_width ? ((i / this->border_width) * Metatile::pixelHeight()) : 0;
painter.drawImage(x, y, metatile_image);
}
painter.end();
if (changed_any) {

View File

@ -501,7 +501,7 @@ bool Tileset::loadTilesImage(QImage *importedImage) {
image = QImage(this->tilesImagePath).convertToFormat(QImage::Format_Indexed8, Qt::ThresholdDither);
} else {
// Use default image
image = QImage(8, 8, QImage::Format_Indexed8);
image = QImage(Tile::pixelWidth(), Tile::pixelHeight(), QImage::Format_Indexed8);
}
// Validate image contains 16 colors.
@ -517,11 +517,9 @@ bool Tileset::loadTilesImage(QImage *importedImage) {
}
QList<QImage> tiles;
int w = 8;
int h = 8;
for (int y = 0; y < image.height(); y += h)
for (int x = 0; x < image.width(); x += w) {
QImage tile = image.copy(x, y, w, h);
for (int y = 0; y < image.height(); y += Tile::pixelHeight())
for (int x = 0; x < image.width(); x += Tile::pixelWidth()) {
QImage tile = image.copy(x, y, Tile::pixelWidth(), Tile::pixelHeight());
tiles.append(tile);
}
this->tilesImage = image;

View File

@ -30,7 +30,7 @@ Editor::Editor(Ui::MainWindow* ui)
{
this->ui = ui;
this->settings = new Settings();
this->cursorMapTileRect = new CursorTileRect(QSize(16,16), qRgb(255, 255, 255));
this->cursorMapTileRect = new CursorTileRect(Metatile::pixelSize(), qRgb(255, 255, 255));
this->map_ruler = new MapRuler(4);
connect(this->map_ruler, &MapRuler::statusChanged, this, &Editor::mapRulerStatusChanged);
@ -1171,7 +1171,7 @@ bool Editor::isMouseInMap() const {
void Editor::setPlayerViewRect(const QRectF &rect) {
delete this->playerViewRect;
this->playerViewRect = new MovableRect(rect, qRgb(255, 255, 255));
this->playerViewRect = new MovableRect(rect, Metatile::pixelSize(), qRgb(255, 255, 255));
updateCursorRectVisibility();
}
@ -1913,8 +1913,8 @@ void Editor::displayMapBorder() {
for (int y = -borderMargins.top(); y < this->layout->getHeight() + borderMargins.bottom(); y += this->layout->getBorderHeight())
for (int x = -borderMargins.left(); x < this->layout->getWidth() + borderMargins.right(); x += this->layout->getBorderWidth()) {
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
item->setX(x * 16);
item->setY(y * 16);
item->setX(x * Metatile::pixelWidth());
item->setY(y * Metatile::pixelHeight());
item->setZValue(ZValue::MapBorder);
scene->addItem(item);
borderItems.append(item);
@ -1962,8 +1962,8 @@ void Editor::displayMapGrid() {
// elements of the scripting API, so they're painted manually in MapView::drawForeground.
this->mapGrid = new QGraphicsItemGroup();
const int pixelMapWidth = this->layout->getWidth() * 16;
const int pixelMapHeight = this->layout->getHeight() * 16;
const int pixelMapWidth = this->layout->pixelWidth();
const int pixelMapHeight = this->layout->pixelHeight();
// The grid can be moved with a user-specified x/y offset. The grid's dash patterns will only wrap in full pattern increments,
// so we draw an additional row/column outside the map that can be revealed as the offset changes.
@ -2476,7 +2476,7 @@ void Editor::setCollisionGraphics() {
// Use the image sheet to create an icon for each collision/elevation combination.
// Any icons for combinations that aren't provided by the image sheet are also created now using default graphics.
const int w = 16, h = 16;
const int w = Metatile::pixelWidth(), h = Metatile::pixelHeight();
imgSheet = imgSheet.scaled(w * imgColumns, h * imgRows);
for (int collision = 0; collision <= Block::getMaxCollision(); collision++) {
// If (collision >= imgColumns) here, it's a valid collision value, but it is not represented with an icon on the image sheet.

View File

@ -1408,7 +1408,7 @@ bool MainWindow::setProjectUI() {
ui->newEventToolButton->setEventTypeVisible(Event::Type::SecretBase, projectConfig.eventSecretBaseEnabled);
ui->newEventToolButton->setEventTypeVisible(Event::Type::CloneObject, projectConfig.eventCloneObjectEnabled);
this->editor->setPlayerViewRect(QRectF(0, 0, 16, 16).marginsAdded(projectConfig.playerViewDistance));
this->editor->setPlayerViewRect(QRectF(QPoint(0,0), Metatile::pixelSize()).marginsAdded(projectConfig.playerViewDistance));
editor->setCollisionGraphics();
ui->spinBox_SelectedElevation->setMaximum(Block::getMaxElevation());
@ -1809,7 +1809,7 @@ void MainWindow::scrollMetatileSelectorToSelection() {
QPoint pos = editor->metatile_selector_item->getMetatileIdCoordsOnWidget(selection.metatileItems.first().metatileId);
QPoint size = editor->metatile_selector_item->getSelectionDimensions();
pos += QPoint(size.x() - 1, size.y() - 1) * 16 / 2; // We want to focus on the center of the whole selection
pos += QPoint((size.x() - 1) * Metatile::pixelWidth(), (size.y() - 1) * Metatile::pixelHeight()) / 2; // We want to focus on the center of the whole selection
pos *= getMetatilesZoomScale();
auto viewport = ui->scrollArea_MetatileSelector->viewport();

View File

@ -2400,12 +2400,11 @@ bool Project::readFieldmapProperties() {
// We can determine whether triple-layer metatiles are in-use by reading this constant.
// If the constant is missing (or is using a value other than 8 or 12) the user must tell
// us whether they're using triple-layer metatiles under Project Settings.
static const int numTilesPerLayer = 4;
int numTilesPerMetatile = it.value();
if (numTilesPerMetatile == 2 * numTilesPerLayer) {
if (numTilesPerMetatile == 2 * Metatile::tilesPerLayer()) {
projectConfig.tripleLayerMetatilesEnabled = false;
this->disabledSettingsNames.insert(numTilesPerMetatileName);
} else if (numTilesPerMetatile == 3 * numTilesPerLayer) {
} else if (numTilesPerMetatile == 3 * Metatile::tilesPerLayer()) {
projectConfig.tripleLayerMetatilesEnabled = true;
this->disabledSettingsNames.insert(numTilesPerMetatileName);
}
@ -3422,14 +3421,25 @@ QString Project::getEmptySpeciesName() {
return projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_species_empty);
}
// Get the distance in metatiles (rounded up) that the player is able to see in each direction in-game.
// Get the distance in pixels that the player is able to see in each direction in-game,
// rounded up to a multiple of a metatile's pixel size.
QMargins Project::getPixelViewDistance() {
QMargins viewDistance = projectConfig.playerViewDistance;
viewDistance.setTop(Util::roundUpToMultiple(viewDistance.top(), Metatile::pixelHeight()));
viewDistance.setBottom(Util::roundUpToMultiple(viewDistance.bottom(), Metatile::pixelHeight()));
viewDistance.setLeft(Util::roundUpToMultiple(viewDistance.left(), Metatile::pixelWidth()));
viewDistance.setRight(Util::roundUpToMultiple(viewDistance.right(), Metatile::pixelWidth()));
return viewDistance;
}
// Get the distance in metatiles that the player is able to see in each direction in-game.
// For the default view distance (i.e. assuming the player is centered in a 240x160 pixel GBA screen) this is 7x5 metatiles.
QMargins Project::getMetatileViewDistance() {
QMargins viewDistance = projectConfig.playerViewDistance;
viewDistance.setTop(qCeil(viewDistance.top() / 16.0));
viewDistance.setBottom(qCeil(viewDistance.bottom() / 16.0));
viewDistance.setLeft(qCeil(viewDistance.left() / 16.0));
viewDistance.setRight(qCeil(viewDistance.right() / 16.0));
QMargins viewDistance = getPixelViewDistance();
viewDistance.setTop(viewDistance.top() / Metatile::pixelHeight());
viewDistance.setBottom(viewDistance.bottom() / Metatile::pixelHeight());
viewDistance.setLeft(viewDistance.left() / Metatile::pixelWidth());
viewDistance.setRight(viewDistance.right() / Metatile::pixelWidth());
return viewDistance;
}

View File

@ -39,13 +39,13 @@ void BorderMetatilesPixmapItem::draw() {
int width = layout->getBorderWidth();
int height = layout->getBorderHeight();
QImage image(16 * width, 16 * height, QImage::Format_RGBA8888);
QImage image(width * Metatile::pixelWidth(), height * Metatile::pixelHeight(), QImage::Format_RGBA8888);
QPainter painter(&image);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int x = i * 16;
int y = j * 16;
int x = i * Metatile::pixelWidth();
int y = j * Metatile::pixelHeight();
QImage metatile_image = getMetatileImage(layout->getBorderMetatileId(i, j), layout);
QPoint metatile_origin = QPoint(x, y);
painter.drawImage(metatile_origin, metatile_image);

View File

@ -100,9 +100,9 @@ void ConnectionPixmapItem::updatePos() {
void ConnectionPixmapItem::updateOrigin() {
if (this->connection->isVertical()) {
this->originX = 0;
this->originY = this->connection->relativePos(true).y() * this->mHeight;
this->originY = this->connection->relativePixelPos(true).y();
} else if (this->connection->isHorizontal()) {
this->originX = this->connection->relativePos(true).x() * this->mWidth;
this->originX = this->connection->relativePixelPos(true).x();
this->originY = 0;
}
updatePos();

View File

@ -3,16 +3,16 @@
#include <QPainter>
QPixmap drawMetatileSelection(MetatileSelection selection, Layout *layout) {
int width = selection.dimensions.x() * 16;
int height = selection.dimensions.y() * 16;
int width = selection.dimensions.x() * Metatile::pixelWidth();
int height = selection.dimensions.y() * Metatile::pixelHeight();
QImage image(width, height, QImage::Format_RGBA8888);
image.fill(QColor(0, 0, 0, 0));
QPainter painter(&image);
for (int i = 0; i < selection.dimensions.x(); i++) {
for (int j = 0; j < selection.dimensions.y(); j++) {
int x = i * 16;
int y = j * 16;
int x = i * Metatile::pixelWidth();
int y = j * Metatile::pixelHeight();
QPoint metatile_origin = QPoint(x, y);
int index = j * selection.dimensions.x() + i;
MetatileSelectionItem item = selection.metatileItems.at(index);

View File

@ -65,6 +65,6 @@ void CursorTileRect::updateLocation(int coordX, int coordY) {
}
}
this->setX(coordX * 16);
this->setY(coordY * 16);
this->setX(coordX * m_tileSize.width());
this->setY(coordY * m_tileSize.height());
}

View File

@ -33,7 +33,7 @@ void MapView::drawForeground(QPainter *painter, const QRectF&) {
painter->save();
if (editor->layout) {
// We're clipping here to hide parts of the grid that are outside the map.
const QRectF mapRect(-0.5, -0.5, editor->layout->getWidth() * 16 + 1.5, editor->layout->getHeight() * 16 + 1.5);
const QRectF mapRect(-0.5, -0.5, editor->layout->pixelWidth() + 1.5, editor->layout->pixelHeight() + 1.5);
painter->setClipping(true);
painter->setClipRect(mapRect);
}

View File

@ -333,8 +333,8 @@ QGifImage* MapImageExporter::createTimelapseGifImage(QProgressDialog *progress)
if (currentHistoryAppliesToFrame(step.historyStack) || step.historyStack->index() == step.initialStackIndex) {
// Either this is relevant edit history, or it's the final frame (which is always rendered). Record the size of the map at this point.
QMargins margins = getMargins(m_map);
canvasSize = canvasSize.expandedTo(QSize(m_layout->getWidth() * 16 + margins.left() + margins.right(),
m_layout->getHeight() * 16 + margins.top() + margins.bottom()));
canvasSize = canvasSize.expandedTo(QSize(m_layout->pixelWidth() + margins.left() + margins.right(),
m_layout->pixelHeight() + margins.top() + margins.bottom()));
}
if (step.historyStack->canUndo()){
step.historyStack->undo();
@ -434,8 +434,8 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
if (!connection->isCardinal()) continue;
Map *connectedMap = connection->targetMap();
if (!connectedMap) continue;
QPoint pos = connection->relativePos();
unvisited.append(StitchedMap{cur.x + (pos.x() * 16), cur.y + (pos.y() * 16), connectedMap});
QPoint pos = connection->relativePixelPos();
unvisited.append(StitchedMap{cur.x + pos.x(), cur.y + pos.y(), connectedMap});
}
}
if (stitchedMaps.isEmpty())
@ -447,7 +447,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress) {
// Determine the overall dimensions of the stitched maps.
QRect dimensions = QRect(0, 0, m_map->getWidth(), m_map->getHeight()) + getMargins(m_map);
for (const StitchedMap &map : stitchedMaps) {
dimensions |= (QRect(map.x, map.y, map.map->getWidth() * 16, map.map->getHeight() * 16) + getMargins(map.map));
dimensions |= (QRect(map.x, map.y, map.map->pixelWidth(), map.map->pixelHeight()) + getMargins(map.map));
}
QPixmap stitchedPixmap(dimensions.width(), dimensions.height());
@ -602,7 +602,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap() {
QMargins MapImageExporter::getMargins(const Map *map) {
QMargins margins;
if (m_settings.showBorder) {
margins = m_project->getMetatileViewDistance() * 16;
margins = m_project->getPixelViewDistance();
} else if (map && connectionsEnabled()) {
for (const auto &connection : map->getConnections()) {
const QString dir = connection->direction();
@ -612,10 +612,10 @@ QMargins MapImageExporter::getMargins(const Map *map) {
if (!targetMap) continue;
QRect rect = targetMap->getConnectionRect(dir);
if (dir == "up") margins.setTop(rect.height() * 16);
else if (dir == "down") margins.setBottom(rect.height() * 16);
else if (dir == "left") margins.setLeft(rect.width() * 16);
else if (dir == "right") margins.setRight(rect.width() * 16);
if (dir == "up") margins.setTop(rect.height());
else if (dir == "down") margins.setBottom(rect.height());
else if (dir == "left") margins.setLeft(rect.width());
else if (dir == "right") margins.setRight(rect.width());
}
}
if (m_settings.showGrid) {
@ -652,7 +652,7 @@ void MapImageExporter::paintBorder(QPainter *painter, Layout *layout) {
// Skip border painting if it would be fully covered by the rest of the map
if (layout->isWithinBounds(QRect(x, y, layout->getBorderWidth(), layout->getBorderHeight())))
continue;
painter->drawPixmap(x * 16, y * 16, layout->border_pixmap);
painter->drawPixmap(x * Metatile::pixelWidth(), y * Metatile::pixelHeight(), layout->border_pixmap);
}
painter->restore();
@ -665,7 +665,7 @@ void MapImageExporter::paintConnections(QPainter *painter, const Map *map) {
for (const auto &connection : map->getConnections()) {
if (!m_settings.showConnections.contains(connection->direction()))
continue;
painter->drawImage(connection->relativePos(true) * 16, connection->render().toImage());
painter->drawImage(connection->relativePixelPos(true), connection->render().toImage());
}
}
@ -693,12 +693,12 @@ void MapImageExporter::paintGrid(QPainter *painter, const Layout *layout) {
if (!m_settings.showGrid)
return;
int w = layout->getWidth() * 16;
int h = layout->getHeight() * 16;
for (int x = 0; x <= w; x += 16) {
int w = layout->pixelWidth();
int h = layout->pixelHeight();
for (int x = 0; x <= w; x += Metatile::pixelWidth()) {
painter->drawLine(x, 0, x, h);
}
for (int y = 0; y <= h; y += 16) {
for (int y = 0; y <= h; y += Metatile::pixelHeight()) {
painter->drawLine(0, y, w, y);
}
}

View File

@ -37,9 +37,11 @@ QPainterPath MapRuler::shape() const {
ruler.addRect(xRuler);
ruler.addRect(yRuler);
ruler = ruler.simplified();
for (int x = 16; x < pixWidth(); x += 16)
int w = Metatile::pixelWidth();
int h = Metatile::pixelHeight();
for (int x = w; x < pixWidth(); x += w)
ruler.addRect(x, xRuler.y(), 0, thickness);
for (int y = 16; y < pixHeight(); y += 16)
for (int y = h; y < pixHeight(); y += h)
ruler.addRect(yRuler.x(), y, thickness, 0);
if (deltaX() && deltaY())
ruler.addPolygon(QVector<QPointF>({ cornerTick.p1(), cornerTick.p2() }));
@ -131,7 +133,9 @@ QPoint MapRuler::snapToWithinBounds(QPoint pos) const {
void MapRuler::updateGeometry() {
prepareGeometryChange();
setPos(QPoint(left() * 16 + 8, top() * 16 + 8));
int w = Metatile::pixelWidth();
int h = Metatile::pixelHeight();
setPos(QPoint(left() * w + w/2, top() * h + h/2));
/* Determine what quadrant the end point is in relative to the anchor point. The anchor
* point is the top-left corner of the metatile the ruler starts in, so a zero-length
* ruler is considered to be in the bottom-right quadrant from the anchor point. */

View File

@ -4,7 +4,7 @@
#include <QPainter>
MetatileLayersItem::MetatileLayersItem(Metatile *metatile, Tileset *primaryTileset, Tileset *secondaryTileset)
: SelectablePixmapItem(16, 16, 2 * projectConfig.getNumLayersInMetatile(), 2),
: SelectablePixmapItem(16, 16, Metatile::tileWidth() * projectConfig.getNumLayersInMetatile(), Metatile::tileHeight()),
metatile(metatile),
primaryTileset(primaryTileset),
secondaryTileset(secondaryTileset)
@ -31,8 +31,8 @@ static const QList<QPoint> tilePositions = {
void MetatileLayersItem::draw() {
const int numLayers = projectConfig.getNumLayersInMetatile();
const int layerWidth = this->cellWidth * 2;
const int layerHeight = this->cellHeight * 2;
const int layerWidth = this->cellWidth * Metatile::tileWidth();
const int layerHeight = this->cellHeight * Metatile::tileHeight();
QPixmap pixmap(numLayers * layerWidth, layerHeight);
QPainter painter(&pixmap);

View File

@ -5,16 +5,17 @@
#include "movablerect.h"
#include "utility.h"
MovableRect::MovableRect(const QRectF &rect, const QRgb &color)
MovableRect::MovableRect(const QRectF &rect, const QSize &cellSize, const QRgb &color)
: QGraphicsRectItem(rect),
baseRect(rect),
cellSize(cellSize),
color(color)
{ }
/// Center rect on grid position (x, y)
void MovableRect::updateLocation(int x, int y) {
setRect(this->baseRect.x() + (x * 16),
this->baseRect.y() + (y * 16),
setRect(this->baseRect.x() + (x * this->cellSize.width()),
this->baseRect.y() + (y * this->cellSize.height()),
this->baseRect.width(),
this->baseRect.height());
}
@ -24,9 +25,9 @@ void MovableRect::updateLocation(int x, int y) {
************************************************************************
******************************************************************************/
ResizableRect::ResizableRect(QObject *parent, int width, int height, QRgb color)
ResizableRect::ResizableRect(QObject *parent, const QSize &cellSize, const QSize &size, const QRgb &color)
: QObject(parent),
MovableRect(QRect(0, 0, width * 16, height * 16), color)
MovableRect(QRect(0, 0, size.width(), size.height()), cellSize, color)
{
setAcceptHoverEvents(true);
setFlags(this->flags() | QGraphicsItem::ItemIsMovable);
@ -114,8 +115,8 @@ void ResizableRect::mousePressEvent(QGraphicsSceneMouseEvent *event) {
}
void ResizableRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
int dx = Util::roundUpToMultiple(event->scenePos().x() - this->clickedPos.x(), 16);
int dy = Util::roundUpToMultiple(event->scenePos().y() - this->clickedPos.y(), 16);
int dx = Util::roundUpToMultiple(event->scenePos().x() - this->clickedPos.x(), this->cellSize.width());
int dy = Util::roundUpToMultiple(event->scenePos().y() - this->clickedPos.y(), this->cellSize.height());
QRect resizedRect = this->clickedRect;
@ -149,20 +150,20 @@ void ResizableRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
break;
}
// Lower limits: smallest possible size is 16x16 square
if (resizedRect.width() < 16) {
// Lower limits: smallest possible size is 1 cell
if (resizedRect.width() < this->cellSize.width()) {
if (dx < 0) { // right sided adjustment made
resizedRect.setWidth(16);
resizedRect.setWidth(this->cellSize.width());
} else { // left sided adjustment slightly more complicated
int dxMax = this->clickedRect.right() - this->clickedRect.left() - 16;
int dxMax = this->clickedRect.right() - this->clickedRect.left() - this->cellSize.width();
resizedRect.adjust(dxMax - dx, 0, 0, 0);
}
}
if (resizedRect.height() < 16) {
if (resizedRect.height() < this->cellSize.height()) {
if (dy < 0) { // bottom
resizedRect.setHeight(16);
resizedRect.setHeight(this->cellSize.height());
} else { // top
int dyMax = this->clickedRect.bottom() - this->clickedRect.top() - 16;
int dyMax = this->clickedRect.bottom() - this->clickedRect.top() - this->cellSize.height();
resizedRect.adjust(0, dyMax - dy, 0, 0);
}
}

View File

@ -23,12 +23,12 @@ PrefabCreationDialog::PrefabCreationDialog(QWidget *parent, MetatileSelector *me
QObject::connect(this->ui->graphicsView_Prefab, &ClickableGraphicsView::clicked, [=](QMouseEvent *event){
auto pos = event->pos();
int selectionWidth = this->selection.dimensions.x() * 16;
int selectionHeight = this->selection.dimensions.y() * 16;
int selectionWidth = this->selection.dimensions.x() * Metatile::pixelWidth();
int selectionHeight = this->selection.dimensions.y() * Metatile::pixelHeight();
if (pos.x() < 0 || pos.x() >= selectionWidth || pos.y() < 0 || pos.y() >= selectionHeight)
return;
int metatileX = pos.x() / 16;
int metatileY = pos.y() / 16;
int metatileX = pos.x() / Metatile::pixelWidth();
int metatileY = pos.y() / Metatile::pixelHeight();
int index = metatileY * this->selection.dimensions.x() + metatileX;
bool toggledState = !this->selection.metatileItems[index].enabled;
this->selection.metatileItems[index].enabled = toggledState;

View File

@ -41,8 +41,9 @@ void CheckeredBgScene::drawBackground(QPainter *painter, const QRectF &rect) {
************************************************************************
******************************************************************************/
BoundedPixmapItem::BoundedPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent) : QGraphicsPixmapItem(pixmap, parent) {
BoundedPixmapItem::BoundedPixmapItem(const QPixmap &pixmap, const QSize &cellSize, QGraphicsItem *parent) : QGraphicsPixmapItem(pixmap, parent) {
setFlags(this->flags() | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges | QGraphicsItem::ItemIsSelectable);
this->cellSize = cellSize;
}
void BoundedPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) {
@ -61,7 +62,8 @@ void BoundedPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem
QVariant BoundedPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value) {
if (change == ItemPositionChange && scene()) {
QPointF newPos = value.toPointF();
return QPointF(Util::roundUpToMultiple(newPos.x(), 16), Util::roundUpToMultiple(newPos.y(), 16));
return QPointF(Util::roundUpToMultiple(newPos.x(), this->cellSize.width()),
Util::roundUpToMultiple(newPos.y(), this->cellSize.height()));
}
else
return QGraphicsItem::itemChange(change, value);
@ -124,11 +126,13 @@ void ResizeLayoutPopup::setupLayoutView() {
this->ui->spinBox_borderHeight->setValue(this->layout->getBorderHeight());
// Layout stuff
this->layoutPixmap = new BoundedPixmapItem(this->layout->pixmap);
this->layoutPixmap = new BoundedPixmapItem(this->layout->pixmap, Metatile::pixelSize());
this->scene->addItem(layoutPixmap);
int maxWidth = this->project->getMaxMapWidth();
int maxHeight = this->project->getMaxMapHeight();
QGraphicsRectItem *cover = new QGraphicsRectItem(-maxWidth * 8, -maxHeight * 8, maxWidth * 16, maxHeight * 16);
int maxPixelWidth = maxWidth * Metatile::pixelWidth() * 2; // *2 to allow reaching max dimension by expanding from 0,0 in either direction
int maxPixelHeight = maxHeight * Metatile::pixelHeight() * 2;
QGraphicsRectItem *cover = new QGraphicsRectItem(-(maxPixelWidth / 2), -(maxPixelHeight / 2), maxPixelWidth, maxPixelHeight);
this->scene->addItem(cover);
this->ui->spinBox_width->setMinimum(1);
@ -136,12 +140,14 @@ void ResizeLayoutPopup::setupLayoutView() {
this->ui->spinBox_height->setMinimum(1);
this->ui->spinBox_height->setMaximum(maxHeight);
this->outline = new ResizableRect(this, this->layout->getWidth(), this->layout->getHeight(), qRgb(255, 0, 255));
this->outline = new ResizableRect(this, Metatile::pixelSize(), this->layout->pixelSize(), qRgb(255, 0, 255));
this->outline->setZValue(Editor::ZValue::ResizeLayoutPopup); // Ensure on top of view
this->outline->setLimit(cover->rect().toAlignedRect());
connect(outline, &ResizableRect::rectUpdated, [=](QRect rect){
// Note: this extra limit check needs access to the project values, so it is done here and not ResizableRect::mouseMoveEvent
int size = this->project->getMapDataSize(rect.width() / 16, rect.height() / 16);
int metatilesWide = rect.width() / Metatile::pixelWidth();
int metatilesTall = rect.height() / Metatile::pixelHeight();
int size = this->project->getMapDataSize(metatilesWide, metatilesTall);
int maxSize = this->project->getMaxMapDataSize();
if (size > maxSize) {
QSize addition = this->project->getMapSizeAddition();
@ -151,8 +157,8 @@ void ResizeLayoutPopup::setupLayoutView() {
.arg(addition.width())
.arg(addition.height())
.arg(maxSize)
.arg(rect.width() / 16)
.arg(rect.height() / 16)
.arg(metatilesWide)
.arg(metatilesTall)
.arg(size),
this);
// adjust rect to last accepted size
@ -160,8 +166,11 @@ void ResizeLayoutPopup::setupLayoutView() {
}
this->scene->setValidRect(rect);
this->outline->setRect(rect);
this->ui->spinBox_width->setValue(rect.width() / 16);
this->ui->spinBox_height->setValue(rect.height() / 16);
const QSignalBlocker b_Width(this->ui->spinBox_width);
const QSignalBlocker b_Height(this->ui->spinBox_height);
this->ui->spinBox_width->setValue(metatilesWide);
this->ui->spinBox_height->setValue(metatilesTall);
});
scene->addItem(outline);
@ -171,7 +180,7 @@ void ResizeLayoutPopup::setupLayoutView() {
this->scale = 1.0;
QRectF rect = this->outline->rect();
const int marginSize = 10 * 16; // Leave a margin of 10 metatiles around the map
const int marginSize = 10 * Metatile::pixelWidth(); // Leave a margin of 10 metatiles around the map
rect += QMargins(marginSize, marginSize, marginSize, marginSize);
this->ui->graphicsView->fitInView(rect, Qt::KeepAspectRatio);
}
@ -179,25 +188,23 @@ void ResizeLayoutPopup::setupLayoutView() {
void ResizeLayoutPopup::on_spinBox_width_valueChanged(int value) {
if (!this->outline) return;
QRectF rect = this->outline->rect();
this->outline->updatePosFromRect(QRect(rect.x(), rect.y(), value * 16, rect.height()));
this->outline->updatePosFromRect(QRect(rect.x(), rect.y(), value * Metatile::pixelWidth(), rect.height()));
}
void ResizeLayoutPopup::on_spinBox_height_valueChanged(int value) {
if (!this->outline) return;
QRectF rect = this->outline->rect();
this->outline->updatePosFromRect(QRect(rect.x(), rect.y(), rect.width(), value * 16));
this->outline->updatePosFromRect(QRect(rect.x(), rect.y(), rect.width(), value * Metatile::pixelHeight()));
}
/// Result is the number of metatiles to add (or subtract) to each side of the map after dimension changes
QMargins ResizeLayoutPopup::getResult() {
QMargins result = QMargins();
result.setLeft(this->layoutPixmap->x() - this->outline->rect().left());
result.setTop(this->layoutPixmap->y() - this->outline->rect().top());
result.setRight(this->outline->rect().right() - (this->layoutPixmap->x() + this->layoutPixmap->pixmap().width()));
result.setBottom(this->outline->rect().bottom() - (this->layoutPixmap->y() + this->layoutPixmap->pixmap().height()));
return result / 16;
result.setLeft((this->layoutPixmap->x() - this->outline->rect().left()) / Metatile::pixelWidth());
result.setTop((this->layoutPixmap->y() - this->outline->rect().top()) / Metatile::pixelHeight());
result.setRight((this->outline->rect().right() - (this->layoutPixmap->x() + this->layoutPixmap->pixmap().width())) / Metatile::pixelWidth());
result.setBottom((this->outline->rect().bottom() - (this->layoutPixmap->y() + this->layoutPixmap->pixmap().height())) / Metatile::pixelHeight());
return result;
}
QSize ResizeLayoutPopup::getBorderResult() {

View File

@ -388,19 +388,21 @@ void TilesetEditor::drawSelectedTiles() {
return;
}
const int imgTileWidth = 16;
const int imgTileHeight = 16;
this->selectedTileScene->clear();
QList<Tile> tiles = this->tileSelector->getSelectedTiles();
QPoint dimensions = this->tileSelector->getSelectionDimensions();
QImage selectionImage(16 * dimensions.x(), 16 * dimensions.y(), QImage::Format_RGBA8888);
QImage selectionImage(imgTileWidth * dimensions.x(), imgTileHeight * dimensions.y(), QImage::Format_RGBA8888);
QPainter painter(&selectionImage);
int tileIndex = 0;
for (int j = 0; j < dimensions.y(); j++) {
for (int i = 0; i < dimensions.x(); i++) {
auto tile = tiles.at(tileIndex);
QImage tileImage = getPalettedTileImage(tile.tileId, this->primaryTileset, this->secondaryTileset, tile.palette, true).scaled(16, 16);
QImage tileImage = getPalettedTileImage(tile.tileId, this->primaryTileset, this->secondaryTileset, tile.palette, true).scaled(imgTileWidth, imgTileHeight);
tile.flip(&tileImage);
tileIndex++;
painter.drawImage(i * 16, j * 16, tileImage);
painter.drawImage(i * imgTileWidth, j * imgTileHeight, tileImage);
}
}
@ -730,18 +732,20 @@ void TilesetEditor::importTilesetTiles(Tileset *tileset) {
} else {
logError(QString("Failed to open image file: '%1'").arg(filepath));
}
if (image.width() == 0 || image.height() == 0 || image.width() % 8 != 0 || image.height() % 8 != 0) {
if (image.width() == 0 || image.height() == 0 || image.width() % Tile::pixelWidth() != 0 || image.height() % Tile::pixelHeight() != 0) {
ErrorMessage::show(QStringLiteral("Failed to import tiles."),
QString("The image dimensions (%1 x %2) are invalid. Width and height must be multiples of 8 pixels.")
QString("The image dimensions (%1x%2) are invalid. The dimensions must be a multiple of %3x%4 pixels.")
.arg(image.width())
.arg(image.height()),
.arg(image.height())
.arg(Tile::pixelWidth())
.arg(Tile::pixelHeight()),
this);
return;
}
// Validate total number of tiles in image.
int numTilesWide = image.width() / 8;
int numTilesHigh = image.height() / 8;
int numTilesWide = image.width() / Tile::pixelWidth();
int numTilesHigh = image.height() / Tile::pixelHeight();
int totalTiles = numTilesHigh * numTilesWide;
int maxAllowedTiles = primary ? Project::getNumTilesPrimary() : Project::getNumTilesTotal() - Project::getNumTilesPrimary();
if (totalTiles > maxAllowedTiles) {

View File

@ -244,19 +244,16 @@ QImage TilesetEditorTileSelector::buildSecondaryTilesIndexedImage() {
}
QImage TilesetEditorTileSelector::buildImage(int tileIdStart, int numTiles) {
const int tileWidth = 8;
const int tileHeight = 8;
int height = qCeil(numTiles / static_cast<double>(this->numTilesWide));
QImage image(this->numTilesWide * tileWidth, height * tileHeight, QImage::Format_RGBA8888);
QImage image(this->numTilesWide * Tile::pixelWidth(), height * Tile::pixelHeight(), QImage::Format_RGBA8888);
image.fill(0);
QPainter painter(&image);
for (int i = 0; i < numTiles; i++) {
QImage tileImage = getGreyscaleTileImage(tileIdStart + i, this->primaryTileset, this->secondaryTileset);
int y = i / this->numTilesWide;
int x = i % this->numTilesWide;
QPoint origin = QPoint(x * tileWidth, y * tileHeight);
painter.drawImage(origin, tileImage);
int x = (i % this->numTilesWide) * Tile::pixelWidth();
int y = (i / this->numTilesWide) * Tile::pixelHeight();
painter.drawImage(x, y, tileImage);
}
painter.end();