Merge branch 'master' of github.com:huderlem/porymap
This commit is contained in:
commit
a4b7f35ced
14 changed files with 463 additions and 32 deletions
|
@ -7,7 +7,9 @@ and this project does **not** adhere to any strict versioning scheme, such as [S
|
||||||
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. If porymap is used on a project that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
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. If porymap is used on a project that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
- Nothing
|
### Added
|
||||||
|
- Add "magic fill" mode to fill tool (hold down CTRL key). This fills all matching metatiles on the map, rather than only the contiguous region.
|
||||||
|
- Add ability to import tileset palettes (JASC, .pal, .tpl, .gpl, .act).
|
||||||
|
|
||||||
## [1.1.0] - 2018-12-27
|
## [1.1.0] - 2018-12-27
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
<height>739</height>
|
<height>739</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>MainWindow</string>
|
<string>MainWindow</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -40,7 +43,7 @@
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QSpinBox" name="spinBox_PaletteId">
|
<widget class="QSpinBox" name="spinBox_PaletteId">
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::StrongFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1651,7 +1654,14 @@
|
||||||
<addaction name="actionUndo"/>
|
<addaction name="actionUndo"/>
|
||||||
<addaction name="actionRedo"/>
|
<addaction name="actionRedo"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuTools">
|
||||||
|
<property name="title">
|
||||||
|
<string>Tools</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionImport_Palette"/>
|
||||||
|
</widget>
|
||||||
<addaction name="menuEdit"/>
|
<addaction name="menuEdit"/>
|
||||||
|
<addaction name="menuTools"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
<action name="actionUndo">
|
<action name="actionUndo">
|
||||||
|
@ -1661,6 +1671,12 @@
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+Z</string>
|
<string>Ctrl+Z</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="shortcutContext">
|
||||||
|
<enum>Qt::WindowShortcut</enum>
|
||||||
|
</property>
|
||||||
|
<property name="priority">
|
||||||
|
<enum>QAction::NormalPriority</enum>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionRedo">
|
<action name="actionRedo">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -1670,6 +1686,11 @@
|
||||||
<string>Ctrl+Y</string>
|
<string>Ctrl+Y</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionImport_Palette">
|
||||||
|
<property name="text">
|
||||||
|
<string>Import Palette</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
<height>600</height>
|
<height>600</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Tileset Editor</string>
|
<string>Tileset Editor</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -44,7 +47,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>272</width>
|
<width>272</width>
|
||||||
<height>538</height>
|
<height>539</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
@ -365,7 +368,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>366</height>
|
<height>367</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
@ -458,7 +461,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>700</width>
|
<width>700</width>
|
||||||
<height>20</height>
|
<height>21</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
|
|
|
@ -68,6 +68,7 @@ public:
|
||||||
void _setBlock(int x, int y, Block block);
|
void _setBlock(int x, int y, Block block);
|
||||||
void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
||||||
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
||||||
|
void magicFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
void commit();
|
void commit();
|
||||||
|
|
23
include/core/paletteparser.h
Normal file
23
include/core/paletteparser.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef PALETTEPARSER_H
|
||||||
|
#define PALETTEPARSER_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QRgb>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class PaletteParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PaletteParser();
|
||||||
|
QList<QRgb> parse(QString filepath, bool *error);
|
||||||
|
private:
|
||||||
|
QList<QRgb> parsePal(QString filepath, bool *error);
|
||||||
|
QList<QRgb> parseJASC(QString filepath, bool *error);
|
||||||
|
QList<QRgb> parseAdvanceMapPal(QString filepath, bool *error);
|
||||||
|
QList<QRgb> parseAdobeColorTable(QString filepath, bool *error);
|
||||||
|
QList<QRgb> parseTileLayerPro(QString filepath, bool *error);
|
||||||
|
QList<QRgb> parseAdvancePaletteEditor(QString filepath, bool *error);
|
||||||
|
int clampColorValue(int value);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PALETTEPARSER_H
|
|
@ -18,6 +18,7 @@ public:
|
||||||
void updateMovementPermissionSelection(QGraphicsSceneMouseEvent *event);
|
void updateMovementPermissionSelection(QGraphicsSceneMouseEvent *event);
|
||||||
virtual void paint(QGraphicsSceneMouseEvent*);
|
virtual void paint(QGraphicsSceneMouseEvent*);
|
||||||
virtual void floodFill(QGraphicsSceneMouseEvent*);
|
virtual void floodFill(QGraphicsSceneMouseEvent*);
|
||||||
|
virtual void magicFill(QGraphicsSceneMouseEvent*);
|
||||||
virtual void pick(QGraphicsSceneMouseEvent*);
|
virtual void pick(QGraphicsSceneMouseEvent*);
|
||||||
virtual void draw(bool ignoreCache = false);
|
virtual void draw(bool ignoreCache = false);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ private:
|
||||||
void refreshColors();
|
void refreshColors();
|
||||||
void refreshColor(int);
|
void refreshColor(int);
|
||||||
void setColor(int);
|
void setColor(int);
|
||||||
void commitEditHistory();
|
void commitEditHistory(int paletteid);
|
||||||
void setColorsFromHistory(PaletteHistoryItem*, int);
|
void setColorsFromHistory(PaletteHistoryItem*, int);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -54,6 +54,7 @@ private slots:
|
||||||
void on_spinBox_PaletteId_valueChanged(int arg1);
|
void on_spinBox_PaletteId_valueChanged(int arg1);
|
||||||
void on_actionUndo_triggered();
|
void on_actionUndo_triggered();
|
||||||
void on_actionRedo_triggered();
|
void on_actionRedo_triggered();
|
||||||
|
void on_actionImport_Palette_triggered();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PALETTEEDITOR_H
|
#endif // PALETTEEDITOR_H
|
||||||
|
|
|
@ -22,6 +22,7 @@ SOURCES += src/core/block.cpp \
|
||||||
src/core/map.cpp \
|
src/core/map.cpp \
|
||||||
src/core/maplayout.cpp \
|
src/core/maplayout.cpp \
|
||||||
src/core/metatile.cpp \
|
src/core/metatile.cpp \
|
||||||
|
src/core/paletteparser.cpp \
|
||||||
src/core/parseutil.cpp \
|
src/core/parseutil.cpp \
|
||||||
src/core/tile.cpp \
|
src/core/tile.cpp \
|
||||||
src/core/tileset.cpp \
|
src/core/tileset.cpp \
|
||||||
|
@ -64,6 +65,7 @@ HEADERS += include/core/block.h \
|
||||||
include/core/mapconnection.h \
|
include/core/mapconnection.h \
|
||||||
include/core/maplayout.h \
|
include/core/maplayout.h \
|
||||||
include/core/metatile.h \
|
include/core/metatile.h \
|
||||||
|
include/core/paletteparser.h \
|
||||||
include/core/parseutil.h \
|
include/core/parseutil.h \
|
||||||
include/core/tile.h \
|
include/core/tile.h \
|
||||||
include/core/tileset.h \
|
include/core/tileset.h \
|
||||||
|
|
|
@ -412,6 +412,26 @@ void Map::floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::magicFillCollisionElevation(int initialX, int initialY, uint16_t collision, uint16_t elevation) {
|
||||||
|
Block *block = getBlock(initialX, initialY);
|
||||||
|
if (block && (block->collision != collision || block->elevation != elevation)) {
|
||||||
|
uint old_coll = block->collision;
|
||||||
|
uint old_elev = block->elevation;
|
||||||
|
|
||||||
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
|
block = getBlock(x, y);
|
||||||
|
if (block && block->collision == old_coll && block->elevation == old_elev) {
|
||||||
|
block->collision = collision;
|
||||||
|
block->elevation = elevation;
|
||||||
|
_setBlock(x, y, *block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QList<Event *> Map::getAllEvents() {
|
QList<Event *> Map::getAllEvents() {
|
||||||
QList<Event*> all;
|
QList<Event*> all;
|
||||||
for (QList<Event*> list : events.values()) {
|
for (QList<Event*> list : events.values()) {
|
||||||
|
|
278
src/core/paletteparser.cpp
Normal file
278
src/core/paletteparser.cpp
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
#include "paletteparser.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
PaletteParser::PaletteParser()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parse(QString filepath, bool *error) {
|
||||||
|
QFileInfo info(filepath);
|
||||||
|
QString extension = info.completeSuffix();
|
||||||
|
if (extension.isNull()) {
|
||||||
|
logError(QString("Failed to parse palette file '%1' because it has an unrecognized extension '%2'").arg(filepath).arg(extension));
|
||||||
|
*error = true;
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extension = extension.toLower();
|
||||||
|
if (extension == "pal") {
|
||||||
|
return parsePal(filepath, error);
|
||||||
|
} else if (extension == "act") {
|
||||||
|
return parseAdobeColorTable(filepath, error);
|
||||||
|
} else if (extension == "tpl") {
|
||||||
|
return parseTileLayerPro(filepath, error);
|
||||||
|
} else if (extension == "gpl") {
|
||||||
|
return parseAdvancePaletteEditor(filepath, error);
|
||||||
|
} else {
|
||||||
|
logError(QString("Unsupported palette file. Supported formats are: .pal"));
|
||||||
|
*error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parsePal(QString filepath, bool *error) {
|
||||||
|
QFile file(filepath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Could not open palette file '%1': ").arg(filepath) + file.errorString());
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
QString firstLine = in.readLine();
|
||||||
|
if (firstLine == "JASC-PAL") {
|
||||||
|
file.close();
|
||||||
|
return parseJASC(filepath, error);
|
||||||
|
} else {
|
||||||
|
file.close();
|
||||||
|
return parseAdvanceMapPal(filepath, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parseJASC(QString filepath, bool *error) {
|
||||||
|
QFile file(filepath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Could not open JASC palette file '%1': ").arg(filepath) + file.errorString());
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
if (in.readLine() != "JASC-PAL") {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("JASC palette file '%1' had an unexpected format. First line must be 'JASC-PAL'.").arg(filepath));
|
||||||
|
file.close();
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.readLine() != "0100") {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("JASC palette file '%1' had an unexpected format. Second line must be '0100'.").arg(filepath));
|
||||||
|
file.close();
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString numColorsStr = in.readLine();
|
||||||
|
bool numOk;
|
||||||
|
int numColors = numColorsStr.toInt(&numOk);
|
||||||
|
if (!numOk) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("JASC palette file '%1' had an unexpected format. Third line must be the number of colors.").arg(filepath));
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> palette;
|
||||||
|
QRegularExpression re("(?<red>\\d+)\\s(?<green>\\d+)\\s(?<blue>\\d+)");
|
||||||
|
while (!in.atEnd() && numColors > 0) {
|
||||||
|
numColors--;
|
||||||
|
QString line = in.readLine();
|
||||||
|
QRegularExpressionMatch match = re.match(line);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QString redStr = match.captured("red");
|
||||||
|
QString greenStr = match.captured("green");
|
||||||
|
QString blueStr = match.captured("blue");
|
||||||
|
bool redOk, greenOk, blueOk;
|
||||||
|
int red = redStr.toInt(&redOk);
|
||||||
|
int green = greenStr.toInt(&greenOk);
|
||||||
|
int blue = blueStr.toInt(&blueOk);
|
||||||
|
if (!redOk || !greenOk || !blueOk) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("JASC palette file '%1' had an unexpected format. Invalid color '%2'.").arg(filepath).arg(line));
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
palette.append(qRgb(this->clampColorValue(red),
|
||||||
|
this->clampColorValue(green),
|
||||||
|
this->clampColorValue(blue)));
|
||||||
|
} else {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("JASC palette file '%1' had an unexpected format. Invalid color '%2'.").arg(filepath).arg(line));
|
||||||
|
file.close();
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parseAdvanceMapPal(QString filepath, bool *error) {
|
||||||
|
QFile file(filepath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Could not open Advance Map palette file '%1': ").arg(filepath) + file.errorString());
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray in = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (in.length() % 4 != 0) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Advance Map palette file '%1' had an unexpected format. File's length must be a multiple of 4, but the length is %2.").arg(filepath).arg(in.length()));
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> palette;
|
||||||
|
int i = 0;
|
||||||
|
while (i < in.length()) {
|
||||||
|
unsigned char blue = static_cast<unsigned char>(in.at(i));
|
||||||
|
unsigned char green = static_cast<unsigned char>(in.at(i + 1));
|
||||||
|
unsigned char red = static_cast<unsigned char>(in.at(i + 2));
|
||||||
|
palette.append(qRgb(this->clampColorValue(red),
|
||||||
|
this->clampColorValue(green),
|
||||||
|
this->clampColorValue(blue)));
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parseAdobeColorTable(QString filepath, bool *error) {
|
||||||
|
QFile file(filepath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Could not open Adobe Color Table palette file '%1': ").arg(filepath) + file.errorString());
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray in = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (in.length() != 0x300) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Adobe Color Table palette file '%1' had an unexpected format. File's length must be exactly 768, but the length is %2.").arg(filepath).arg(in.length()));
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> palette;
|
||||||
|
int i = 0;
|
||||||
|
while (i < in.length()) {
|
||||||
|
unsigned char red = static_cast<unsigned char>(in.at(i));
|
||||||
|
unsigned char green = static_cast<unsigned char>(in.at(i + 1));
|
||||||
|
unsigned char blue = static_cast<unsigned char>(in.at(i + 2));
|
||||||
|
palette.append(qRgb(this->clampColorValue(red),
|
||||||
|
this->clampColorValue(green),
|
||||||
|
this->clampColorValue(blue)));
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parseTileLayerPro(QString filepath, bool *error) {
|
||||||
|
QFile file(filepath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Could not open Tile Layer Pro palette file '%1': ").arg(filepath) + file.errorString());
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray in = file.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (in.length() < 4 || in.at(0) != 'T' || in.at(1) != 'L' || in.at(2) != 'P' || in.at(3) != 0) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Tile Layer Pro palette file '%1' had an unexpected format. The TLP header is missing.").arg(filepath).arg(in.length()));
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.length() != 0x304) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Tile Layer Pro palette file '%1' had an unexpected format. File's length must be exactly 772, but the length is %2.").arg(filepath).arg(in.length()));
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> palette;
|
||||||
|
int i = 4;
|
||||||
|
while (i < in.length()) {
|
||||||
|
unsigned char red = static_cast<unsigned char>(in.at(i));
|
||||||
|
unsigned char green = static_cast<unsigned char>(in.at(i + 1));
|
||||||
|
unsigned char blue = static_cast<unsigned char>(in.at(i + 2));
|
||||||
|
palette.append(qRgb(this->clampColorValue(red),
|
||||||
|
this->clampColorValue(green),
|
||||||
|
this->clampColorValue(blue)));
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> PaletteParser::parseAdvancePaletteEditor(QString filepath, bool *error) {
|
||||||
|
QFile file(filepath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("Could not open GPL palette file '%1': ").arg(filepath) + file.errorString());
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
if (in.readLine() != "[APE Palette]") {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("GPL palette file '%1' had an unexpected format. First line must be '[APE Palette]'.").arg(filepath));
|
||||||
|
file.close();
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QRgb> palette;
|
||||||
|
while (!in.atEnd()) {
|
||||||
|
QString line = in.readLine().trimmed();
|
||||||
|
if (line.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
unsigned int raw = line.toUInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
*error = true;
|
||||||
|
logError(QString("GPL palette file '%1' had an unexpected format. Invalid color '%2'.").arg(filepath).arg(line));
|
||||||
|
file.close();
|
||||||
|
return QList<QRgb>();
|
||||||
|
}
|
||||||
|
|
||||||
|
raw = ((raw & 0xFF)<< 8) | ((raw >> 8) & 0xFF);
|
||||||
|
int red = (raw & 0x1F) * 8;
|
||||||
|
int green = ((raw >> 5) & 0x1F) * 8;
|
||||||
|
int blue = ((raw >> 10) & 0x1F) * 8;
|
||||||
|
palette.append(qRgb(this->clampColorValue(red),
|
||||||
|
this->clampColorValue(green),
|
||||||
|
this->clampColorValue(blue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PaletteParser::clampColorValue(int value) {
|
||||||
|
if (value < 0) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
if (value > 255) {
|
||||||
|
value = 255;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
|
@ -2,5 +2,6 @@
|
||||||
|
|
||||||
Settings::Settings()
|
Settings::Settings()
|
||||||
{
|
{
|
||||||
|
this->smartPathsEnabled = false;
|
||||||
|
this->betterCursors = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,18 @@ void CollisionPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollisionPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
|
||||||
|
if (map) {
|
||||||
|
QPointF pos = event->pos();
|
||||||
|
int x = static_cast<int>(pos.x()) / 16;
|
||||||
|
int y = static_cast<int>(pos.y()) / 16;
|
||||||
|
uint16_t collision = this->movementPermissionsSelector->getSelectedCollision();
|
||||||
|
uint16_t elevation = this->movementPermissionsSelector->getSelectedElevation();
|
||||||
|
map->magicFillCollisionElevation(x, y, collision, elevation);
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
|
void CollisionPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
|
||||||
QPointF pos = event->pos();
|
QPointF pos = event->pos();
|
||||||
int x = static_cast<int>(pos.x()) / 16;
|
int x = static_cast<int>(pos.x()) / 16;
|
||||||
|
|
|
@ -257,28 +257,25 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
|
||||||
map->commit();
|
map->commit();
|
||||||
} else {
|
} else {
|
||||||
QPointF pos = event->pos();
|
QPointF pos = event->pos();
|
||||||
int x = static_cast<int>(pos.x()) / 16;
|
int initialX = static_cast<int>(pos.x()) / 16;
|
||||||
int y = static_cast<int>(pos.y()) / 16;
|
int initialY = static_cast<int>(pos.y()) / 16;
|
||||||
Block *block = map->getBlock(x, y);
|
Block *block = map->getBlock(initialX, initialY);
|
||||||
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
|
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
|
||||||
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
|
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
|
||||||
uint16_t tile = block->tile;
|
uint16_t tile = block->tile;
|
||||||
for (int curY = 0; curY < map->getWidth(); curY++) {
|
|
||||||
for (int curX = 0; curX < map->getWidth(); curX++) {
|
|
||||||
Block *block = map->getBlock(curX, curY);
|
|
||||||
if (!block) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xDiff = curX - x;
|
for (int y = 0; y < map->getHeight(); y++) {
|
||||||
int yDiff = curY - y;
|
for (int x = 0; x < map->getWidth(); x++) {
|
||||||
int i = xDiff % selectionDimensions.x();
|
block = map->getBlock(x, y);
|
||||||
int j = yDiff % selectionDimensions.y();
|
if (block && block->tile == tile) {
|
||||||
if (i < 0) i = selectionDimensions.x() + i;
|
int xDiff = x - initialX;
|
||||||
if (j < 0) j = selectionDimensions.y() + j;
|
int yDiff = y - initialY;
|
||||||
if (block->tile == tile) {
|
int i = xDiff % selectionDimensions.x();
|
||||||
|
int j = yDiff % selectionDimensions.y();
|
||||||
|
if (i < 0) i = selectionDimensions.x() + i;
|
||||||
|
if (j < 0) j = selectionDimensions.y() + j;
|
||||||
block->tile = selectedMetatiles->at(j * selectionDimensions.x() + i);
|
block->tile = selectedMetatiles->at(j * selectionDimensions.x() + i);
|
||||||
map->_setBlock(curX, curY, *block);
|
map->_setBlock(x, y, *block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,12 +289,18 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
|
||||||
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
|
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
|
||||||
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
|
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
|
||||||
|
|
||||||
|
int numMetatiles = map->getWidth() * map->getHeight();
|
||||||
|
bool *visited = new bool[numMetatiles];
|
||||||
|
for (int i = 0; i < numMetatiles; i++)
|
||||||
|
visited[i] = false;
|
||||||
|
|
||||||
QList<QPoint> todo;
|
QList<QPoint> todo;
|
||||||
todo.append(QPoint(initialX, initialY));
|
todo.append(QPoint(initialX, initialY));
|
||||||
while (todo.length()) {
|
while (todo.length()) {
|
||||||
QPoint point = todo.takeAt(0);
|
QPoint point = todo.takeAt(0);
|
||||||
int x = point.x();
|
int x = point.x();
|
||||||
int y = point.y();
|
int y = point.y();
|
||||||
|
visited[x + y * map->getWidth()] = true;
|
||||||
|
|
||||||
Block *block = map->getBlock(x, y);
|
Block *block = map->getBlock(x, y);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
|
@ -316,19 +319,25 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
|
||||||
block->tile = tile;
|
block->tile = tile;
|
||||||
map->_setBlock(x, y, *block);
|
map->_setBlock(x, y, *block);
|
||||||
}
|
}
|
||||||
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
|
if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
|
||||||
todo.append(QPoint(x + 1, y));
|
todo.append(QPoint(x + 1, y));
|
||||||
|
visited[x + 1 + y * map->getWidth()] = true;
|
||||||
}
|
}
|
||||||
if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
|
if (!visited[x - 1 + y * map->getWidth()] && (block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
|
||||||
todo.append(QPoint(x - 1, y));
|
todo.append(QPoint(x - 1, y));
|
||||||
|
visited[x - 1 + y * map->getWidth()] = true;
|
||||||
}
|
}
|
||||||
if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
|
if (!visited[x + (y + 1) * map->getWidth()] && (block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
|
||||||
todo.append(QPoint(x, y + 1));
|
todo.append(QPoint(x, y + 1));
|
||||||
|
visited[x + (y + 1) * map->getWidth()] = true;
|
||||||
}
|
}
|
||||||
if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
|
if (!visited[x + (y - 1) * map->getWidth()] && (block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
|
||||||
todo.append(QPoint(x, y - 1));
|
todo.append(QPoint(x, y - 1));
|
||||||
|
visited[x + (y - 1) * map->getWidth()] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete[] visited;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
|
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "paletteeditor.h"
|
#include "paletteeditor.h"
|
||||||
#include "ui_paletteeditor.h"
|
#include "ui_paletteeditor.h"
|
||||||
|
#include "paletteparser.h"
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset *secondaryTileset, QWidget *parent) :
|
PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset *secondaryTileset, QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
|
@ -108,7 +112,7 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset
|
||||||
this->initColorSliders();
|
this->initColorSliders();
|
||||||
this->refreshColorSliders();
|
this->refreshColorSliders();
|
||||||
this->refreshColors();
|
this->refreshColors();
|
||||||
this->commitEditHistory();
|
this->commitEditHistory(this->ui->spinBox_PaletteId->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
PaletteEditor::~PaletteEditor()
|
PaletteEditor::~PaletteEditor()
|
||||||
|
@ -194,18 +198,20 @@ void PaletteEditor::setColor(int colorIndex) {
|
||||||
: this->secondaryTileset;
|
: this->secondaryTileset;
|
||||||
(*tileset->palettes)[paletteNum][colorIndex] = qRgb(red, green, blue);
|
(*tileset->palettes)[paletteNum][colorIndex] = qRgb(red, green, blue);
|
||||||
this->refreshColor(colorIndex);
|
this->refreshColor(colorIndex);
|
||||||
this->commitEditHistory();
|
this->commitEditHistory(paletteNum);
|
||||||
emit this->changedPaletteColor();
|
emit this->changedPaletteColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaletteEditor::on_spinBox_PaletteId_valueChanged(int paletteId) {
|
void PaletteEditor::on_spinBox_PaletteId_valueChanged(int paletteId) {
|
||||||
this->refreshColorSliders();
|
this->refreshColorSliders();
|
||||||
this->refreshColors();
|
this->refreshColors();
|
||||||
|
if (!this->palettesHistory[paletteId].current()) {
|
||||||
|
this->commitEditHistory(paletteId);
|
||||||
|
}
|
||||||
emit this->changedPalette(paletteId);
|
emit this->changedPalette(paletteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaletteEditor::commitEditHistory() {
|
void PaletteEditor::commitEditHistory(int paletteId) {
|
||||||
int paletteId = this->ui->spinBox_PaletteId->value();
|
|
||||||
QList<QRgb> colors;
|
QList<QRgb> colors;
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
colors.append(qRgb(this->sliders[i][0]->value() * 8, this->sliders[i][1]->value() * 8, this->sliders[i][2]->value() * 8));
|
colors.append(qRgb(this->sliders[i][0]->value() * 8, this->sliders[i][1]->value() * 8, this->sliders[i][2]->value() * 8));
|
||||||
|
@ -243,3 +249,54 @@ void PaletteEditor::setColorsFromHistory(PaletteHistoryItem *history, int palett
|
||||||
this->refreshColors();
|
this->refreshColors();
|
||||||
emit this->changedPaletteColor();
|
emit this->changedPaletteColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PaletteEditor::on_actionImport_Palette_triggered()
|
||||||
|
{
|
||||||
|
QString filepath = QFileDialog::getOpenFileName(
|
||||||
|
this,
|
||||||
|
QString("Import Tileset Palette"),
|
||||||
|
this->project->root,
|
||||||
|
"Palette Files (*.pal *.act *tpl *gpl)");
|
||||||
|
if (filepath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaletteParser parser;
|
||||||
|
bool error = false;
|
||||||
|
QList<QRgb> palette = parser.parse(filepath, &error);
|
||||||
|
if (error) {
|
||||||
|
QMessageBox msgBox(this);
|
||||||
|
msgBox.setText("Failed to import palette.");
|
||||||
|
QString message = QString("The palette file could not be processed. View porymap.log for specific errors.");
|
||||||
|
msgBox.setInformativeText(message);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||||
|
msgBox.setIcon(QMessageBox::Icon::Critical);
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (palette.length() < 16) {
|
||||||
|
QMessageBox msgBox(this);
|
||||||
|
msgBox.setText("Failed to import palette.");
|
||||||
|
QString message = QString("The palette file has %1 colors, but it must have 16 colors.").arg(palette.length());
|
||||||
|
msgBox.setInformativeText(message);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Ok);
|
||||||
|
msgBox.setIcon(QMessageBox::Icon::Critical);
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int paletteId = this->ui->spinBox_PaletteId->value();
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (paletteId < Project::getNumPalettesPrimary()) {
|
||||||
|
(*this->primaryTileset->palettes)[paletteId][i] = palette.at(i);
|
||||||
|
} else {
|
||||||
|
(*this->secondaryTileset->palettes)[paletteId][i] = palette.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->refreshColorSliders();
|
||||||
|
this->refreshColors();
|
||||||
|
this->commitEditHistory(paletteId);
|
||||||
|
emit this->changedPaletteColor();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue