Merge pull request #536 from GriffinRichards/4bpp
Support 8BPP tileset tile images
This commit is contained in:
commit
d28849a533
9 changed files with 41 additions and 26 deletions
|
@ -7,6 +7,9 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp
|
|||
The **"Breaking Changes"** listed below are changes that have been made in the decompilation projects (e.g. pokeemerald), which porymap requires in order to work properly. It also includes changes to the scripting API that may change the behavior of existing porymap scripts. If porymap is used with a project or API script that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Support for 8BPP tileset tile images.
|
||||
|
||||
### Changed
|
||||
- The Palette Editor now remembers the Bit Depth setting.
|
||||
- The min/max levels on the Wild Pokémon tab will now adjust automatically if they invalidate each other.
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
QList<QList<QRgb>> palettes;
|
||||
QList<QList<QRgb>> palettePreviews;
|
||||
|
||||
bool hasUnsavedTilesImage;
|
||||
|
||||
static Tileset* getMetatileTileset(int, Tileset*, Tileset*);
|
||||
static Tileset* getTileTileset(int, Tileset*, Tileset*);
|
||||
static Metatile* getMetatile(int, Tileset*, Tileset*);
|
||||
|
|
|
@ -13,6 +13,7 @@ QImage getMetatileImage(Metatile*, Tileset*, Tileset*, QList<int>, QList<float>,
|
|||
QImage getTileImage(uint16_t, Tileset*, Tileset*);
|
||||
QImage getPalettedTileImage(uint16_t, Tileset*, Tileset*, int, bool useTruePalettes = false);
|
||||
QImage getGreyscaleTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset);
|
||||
void flattenTo4bppImage(QImage * image);
|
||||
|
||||
static QList<QRgb> greyscalePalette({
|
||||
qRgb(0, 0, 0),
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "selectablepixmapitem.h"
|
||||
#include "paletteutil.h"
|
||||
#include "imageproviders.h"
|
||||
|
||||
#include <memory>
|
||||
using std::shared_ptr;
|
||||
|
@ -127,10 +128,7 @@ public:
|
|||
this->tileset = QImage(tilesetFilepath);
|
||||
this->format = format;
|
||||
if (this->tileset.format() == QImage::Format::Format_Indexed8 && this->format == TilemapFormat::BPP_4) {
|
||||
// Squash pixel data to fit 4BPP. Allows project repo to use 8BPP images for 4BPP tilemaps
|
||||
uchar * pixel = this->tileset.bits();
|
||||
for (int i = 0; i < this->tileset.sizeInBytes(); i++, pixel++)
|
||||
*pixel %= 16;
|
||||
flattenTo4bppImage(&this->tileset);
|
||||
}
|
||||
bool err;
|
||||
if (!palFilepath.isEmpty()) {
|
||||
|
|
|
@ -22,7 +22,8 @@ Tileset::Tileset(const Tileset &other)
|
|||
palettePaths(other.palettePaths),
|
||||
metatileLabels(other.metatileLabels),
|
||||
palettes(other.palettes),
|
||||
palettePreviews(other.palettePreviews)
|
||||
palettePreviews(other.palettePreviews),
|
||||
hasUnsavedTilesImage(false)
|
||||
{
|
||||
for (auto tile : other.tiles) {
|
||||
tiles.append(tile.copy());
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mapparser.h"
|
||||
#include "prefab.h"
|
||||
#include "montabwidget.h"
|
||||
#include "imageexport.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QClipboard>
|
||||
|
@ -1280,7 +1281,7 @@ void MainWindow::on_actionNew_Tileset_triggered() {
|
|||
}
|
||||
newSet.palettes[0][1] = qRgb(255,0,255);
|
||||
newSet.palettePreviews[0][1] = qRgb(255,0,255);
|
||||
editor->project->saveTilesetTilesImage(&newSet);
|
||||
exportIndexed4BPPPng(newSet.tilesImage, newSet.tilesImagePath);
|
||||
editor->project->saveTilesetMetatiles(&newSet);
|
||||
editor->project->saveTilesetMetatileAttributes(&newSet);
|
||||
editor->project->saveTilesetPalettes(&newSet);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "paletteutil.h"
|
||||
#include "tile.h"
|
||||
#include "tileset.h"
|
||||
#include "imageexport.h"
|
||||
#include "map.h"
|
||||
|
||||
#include "orderedjson.h"
|
||||
|
@ -1008,7 +1007,15 @@ void Project::saveTilesetMetatiles(Tileset *tileset) {
|
|||
}
|
||||
|
||||
void Project::saveTilesetTilesImage(Tileset *tileset) {
|
||||
exportIndexed4BPPPng(tileset->tilesImage, tileset->tilesImagePath);
|
||||
// Only write the tiles image if it was changed.
|
||||
// Porymap will only ever change an existing tiles image by importing a new one.
|
||||
if (tileset->hasUnsavedTilesImage) {
|
||||
if (!tileset->tilesImage.save(tileset->tilesImagePath, "PNG")) {
|
||||
logError(QString("Failed to save tiles image '%1'").arg(tileset->tilesImagePath));
|
||||
return;
|
||||
}
|
||||
tileset->hasUnsavedTilesImage = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Project::saveTilesetPalettes(Tileset *tileset) {
|
||||
|
@ -1350,6 +1357,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
|
|||
QImage image;
|
||||
if (QFile::exists(tileset->tilesImagePath)) {
|
||||
image = QImage(tileset->tilesImagePath).convertToFormat(QImage::Format_Indexed8, Qt::ThresholdDither);
|
||||
flattenTo4bppImage(&image);
|
||||
} else {
|
||||
image = QImage(8, 8, QImage::Format_Indexed8);
|
||||
}
|
||||
|
|
|
@ -169,3 +169,12 @@ QImage getPalettedTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *s
|
|||
QImage getGreyscaleTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
return getColoredTileImage(tileId, primaryTileset, secondaryTileset, greyscalePalette);
|
||||
}
|
||||
|
||||
// gbagfx allows 4bpp image data to be represented with 8bpp .png files by considering only the lower 4 bits of each pixel.
|
||||
// Reproduce that here to support this type of image use.
|
||||
void flattenTo4bppImage(QImage * image) {
|
||||
if (!image) return;
|
||||
uchar * pixel = image->bits();
|
||||
for (int i = 0; i < image->sizeInBytes(); i++, pixel++)
|
||||
*pixel %= 16;
|
||||
}
|
||||
|
|
|
@ -701,15 +701,6 @@ void TilesetEditor::importTilesetTiles(Tileset *tileset, bool primary) {
|
|||
msgBox.setIcon(QMessageBox::Icon::Critical);
|
||||
msgBox.exec();
|
||||
return;
|
||||
} else if (palette.length() != 16) {
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setText("Failed to import palette.");
|
||||
QString message = QString("The palette must have exactly 16 colors, but it has %1.").arg(palette.length());
|
||||
msgBox.setInformativeText(message);
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
msgBox.setIcon(QMessageBox::Icon::Critical);
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<QRgb> colorTable = palette.toVector();
|
||||
|
@ -717,20 +708,21 @@ void TilesetEditor::importTilesetTiles(Tileset *tileset, bool primary) {
|
|||
}
|
||||
|
||||
// Validate image is properly indexed to 16 colors.
|
||||
if (image.colorCount() != 16) {
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setText("Failed to import tiles.");
|
||||
msgBox.setInformativeText(QString("The image must be indexed and contain 16 total colors, or it must be un-indexed. The provided image has %1 indexed colors.")
|
||||
.arg(image.colorCount()));
|
||||
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||
msgBox.setIcon(QMessageBox::Icon::Critical);
|
||||
msgBox.exec();
|
||||
return;
|
||||
int colorCount = image.colorCount();
|
||||
if (colorCount > 16) {
|
||||
flattenTo4bppImage(&image);
|
||||
} else if (colorCount < 16) {
|
||||
QVector<QRgb> colorTable = image.colorTable();
|
||||
for (int i = colorTable.length(); i < 16; i++) {
|
||||
colorTable.append(Qt::black);
|
||||
}
|
||||
image.setColorTable(colorTable);
|
||||
}
|
||||
|
||||
this->project->loadTilesetTiles(tileset, image);
|
||||
this->refresh();
|
||||
this->hasUnsavedChanges = true;
|
||||
tileset->hasUnsavedTilesImage = true;
|
||||
}
|
||||
|
||||
void TilesetEditor::closeEvent(QCloseEvent *event)
|
||||
|
|
Loading…
Reference in a new issue