[nostalgia/core] Add basic color selection and basic tilesheet editing
This commit is contained in:
parent
2e5263764c
commit
e407ad7246
@ -17,6 +17,7 @@ elseif(NOSTALGIA_BUILD_TYPE STREQUAL "Native")
|
|||||||
add_subdirectory(userland)
|
add_subdirectory(userland)
|
||||||
endif()
|
endif()
|
||||||
if(NOSTALGIA_BUILD_STUDIO)
|
if(NOSTALGIA_BUILD_STUDIO)
|
||||||
|
add_subdirectory(qt)
|
||||||
add_subdirectory(studio)
|
add_subdirectory(studio)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -149,6 +149,32 @@ Color32 toColor32(Color16 nc) {
|
|||||||
return a | (b << 8) | (g << 16) | (r << 24);
|
return a | (b << 8) | (g << 16) | (r << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t red32(Color32 c) {
|
||||||
|
return (c & 0x000000ff) >> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t green32(Color32 c) {
|
||||||
|
return (c & 0x0000ff00) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t blue32(Color32 c) {
|
||||||
|
return (c & 0x00ff0000) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t red32(Color16 c) {
|
||||||
|
return ((c & 0b0000000000011111) >> 0) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t green32(Color16 c) {
|
||||||
|
return ((c & 0b0000001111100000) >> 5) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t blue32(Color16 c) {
|
||||||
|
return ((c & 0b0111110000000000) >> 10) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
void puts(Context *ctx, int column, int row, const char *str) {
|
void puts(Context *ctx, int column, int row, const char *str) {
|
||||||
for (int i = 0; str[i]; i++) {
|
for (int i = 0; str[i]; i++) {
|
||||||
setTile(ctx, 0, column + i, row, charMap[static_cast<int>(str[i])]);
|
setTile(ctx, 0, column + i, row, charMap[static_cast<int>(str[i])]);
|
||||||
|
@ -71,6 +71,19 @@ ox::Error model(T *io, NostalgiaGraphic *ng) {
|
|||||||
|
|
||||||
[[nodiscard]] Color32 toColor32(Color16 nc);
|
[[nodiscard]] Color32 toColor32(Color16 nc);
|
||||||
|
|
||||||
|
[[nodiscard]] uint8_t red32(Color16 c);
|
||||||
|
|
||||||
|
[[nodiscard]] uint8_t green32(Color16 c);
|
||||||
|
|
||||||
|
[[nodiscard]] uint8_t blue32(Color16 c);
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] uint8_t red32(Color32 c);
|
||||||
|
|
||||||
|
[[nodiscard]] uint8_t green32(Color32 c);
|
||||||
|
|
||||||
|
[[nodiscard]] uint8_t blue32(Color32 c);
|
||||||
|
|
||||||
void puts(Context *ctx, int column, int row, const char *str);
|
void puts(Context *ctx, int column, int row, const char *str);
|
||||||
|
|
||||||
void setTile(Context *ctx, int layer, int column, int row, uint8_t tile);
|
void setTile(Context *ctx, int layer, int column, int row, uint8_t tile);
|
||||||
|
@ -64,7 +64,7 @@ ox::Error initConsole(Context *ctx) {
|
|||||||
|
|
||||||
SDL_Color createSDL_Color(Color16 nc) {
|
SDL_Color createSDL_Color(Color16 nc) {
|
||||||
SDL_Color c;
|
SDL_Color c;
|
||||||
// extract the color chanels and scale them up for a 24 bit color
|
// extract the color channels and scale them up for a 24 bit color
|
||||||
c.r = ((nc & 0b0000000000011111) >> 0) * 8;
|
c.r = ((nc & 0b0000000000011111) >> 0) * 8;
|
||||||
c.g = ((nc & 0b0000001111100000) >> 5) * 8;
|
c.g = ((nc & 0b0000001111100000) >> 5) * 8;
|
||||||
c.b = ((nc & 0b0111110000000000) >> 10) * 8;
|
c.b = ((nc & 0b0111110000000000) >> 10) * 8;
|
||||||
|
@ -14,6 +14,7 @@ target_link_libraries(
|
|||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
Qt5::QuickWidgets
|
Qt5::QuickWidgets
|
||||||
NostalgiaStudio
|
NostalgiaStudio
|
||||||
|
NostalgiaCore-Qt
|
||||||
NostalgiaCore
|
NostalgiaCore
|
||||||
OxFS
|
OxFS
|
||||||
OxStd
|
OxStd
|
||||||
|
@ -26,4 +26,10 @@ Rectangle {
|
|||||||
anchors.horizontalCenter: pixel.horizontalCenter
|
anchors.horizontalCenter: pixel.horizontalCenter
|
||||||
anchors.bottom: pixel.bottom
|
anchors.bottom: pixel.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: sheetData.updatePixels([pixel])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,12 @@ Rectangle {
|
|||||||
Grid {
|
Grid {
|
||||||
id: tileGrid
|
id: tileGrid
|
||||||
property int baseTileSize: Math.min(parent.width / tileGrid.columns, parent.height / tileGrid.rows)
|
property int baseTileSize: Math.min(parent.width / tileGrid.columns, parent.height / tileGrid.rows)
|
||||||
width: tileGrid.columns * tileGrid.baseTileSize * 0.85
|
width: tileGrid.columns * tileGrid.baseTileSize * 0.90
|
||||||
height: tileGrid.rows * tileGrid.baseTileSize * 0.85
|
height: tileGrid.rows * tileGrid.baseTileSize * 0.90
|
||||||
anchors.horizontalCenter: tileSheetEditor.horizontalCenter
|
anchors.horizontalCenter: tileSheetEditor.horizontalCenter
|
||||||
anchors.verticalCenter: tileSheetEditor.verticalCenter
|
anchors.verticalCenter: tileSheetEditor.verticalCenter
|
||||||
rows: 2
|
rows: sheetData.rows
|
||||||
columns: 2
|
columns: sheetData.columns
|
||||||
Repeater {
|
Repeater {
|
||||||
model: tileGrid.rows * tileGrid.columns
|
model: tileGrid.rows * tileGrid.columns
|
||||||
Tile {
|
Tile {
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QHeaderView>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
#include <QQuickItem>
|
||||||
#include <QQuickWidget>
|
#include <QQuickWidget>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
@ -17,11 +19,68 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
QColor toQColor(Color16 nc) {
|
||||||
|
const auto r = red32(nc);
|
||||||
|
const auto g = green32(nc);
|
||||||
|
const auto b = blue32(nc);
|
||||||
|
const auto a = 255;
|
||||||
|
return QColor(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QString SheetData::pixel(int index) {
|
QString SheetData::pixel(int index) {
|
||||||
return m_palette[m_pixels[index]];
|
return m_palette[m_pixels[index]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SheetData::updatePixels(QVariantList pixels) {
|
||||||
|
for (auto pi : pixels) {
|
||||||
|
// TODO: replace with push to QUndoStack
|
||||||
|
auto p = qobject_cast<QQuickItem*>(pi.value<QObject*>());
|
||||||
|
p->setProperty("color", m_palette[m_selectedColor]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int SheetData::columns() {
|
||||||
|
return m_columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SheetData::setColumns(int columns) {
|
||||||
|
m_columns = columns;
|
||||||
|
emit columnsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SheetData::rows() {
|
||||||
|
return m_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SheetData::setRows(int rows) {
|
||||||
|
m_rows = rows;
|
||||||
|
emit rowsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList SheetData::palette() {
|
||||||
|
return m_palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SheetData::updatePixels(const studio::Context *ctx, QString ngPath, QString palPath) {
|
||||||
|
auto ng = ctx->project->loadObj<NostalgiaGraphic>(ngPath);
|
||||||
|
std::unique_ptr<NostalgiaPalette> npal;
|
||||||
|
if (palPath == "" && ng->defaultPalette.type() == ox::FileAddressType::Path) {
|
||||||
|
palPath = ng->defaultPalette.getPath().value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
npal = ctx->project->loadObj<NostalgiaPalette>(palPath);
|
||||||
|
qInfo() << "Opened palette" << palPath;
|
||||||
|
} catch (ox::Error) {
|
||||||
|
qWarning() << "Could not open palette" << palPath;
|
||||||
|
}
|
||||||
|
updatePixels(ng.get(), npal.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SheetData::setSelectedColor(int index) {
|
||||||
|
m_selectedColor = index;
|
||||||
|
}
|
||||||
|
|
||||||
void SheetData::updatePixels(const NostalgiaGraphic *ng, const NostalgiaPalette *npal) {
|
void SheetData::updatePixels(const NostalgiaGraphic *ng, const NostalgiaPalette *npal) {
|
||||||
if (!npal) {
|
if (!npal) {
|
||||||
npal = &ng->pal;
|
npal = &ng->pal;
|
||||||
@ -29,8 +88,8 @@ void SheetData::updatePixels(const NostalgiaGraphic *ng, const NostalgiaPalette
|
|||||||
|
|
||||||
// load palette
|
// load palette
|
||||||
for (std::size_t i = 0; i < npal->colors.size(); i++) {
|
for (std::size_t i = 0; i < npal->colors.size(); i++) {
|
||||||
auto c = toColor32(npal->colors[i]);
|
const auto c = toQColor(npal->colors[i]);
|
||||||
auto color = "#" + QString("%1").arg(QString::number(c, 16), 8, '0');
|
const auto color = c.name(QColor::HexArgb);
|
||||||
m_palette.append(color);
|
m_palette.append(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,21 +110,6 @@ void SheetData::updatePixels(const NostalgiaGraphic *ng, const NostalgiaPalette
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SheetData::updatePixels(const studio::Context *ctx, QString ngPath, QString palPath) {
|
|
||||||
auto ng = ctx->project->loadObj<NostalgiaGraphic>(ngPath);
|
|
||||||
std::unique_ptr<NostalgiaPalette> npal;
|
|
||||||
if (palPath == "" && ng->defaultPalette.type() == ox::FileAddressType::Path) {
|
|
||||||
palPath = ng->defaultPalette.getPath().value;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
npal = ctx->project->loadObj<NostalgiaPalette>(palPath);
|
|
||||||
qInfo() << "Opened palette" << palPath;
|
|
||||||
} catch (ox::Error) {
|
|
||||||
qWarning() << "Could not open palette" << palPath;
|
|
||||||
}
|
|
||||||
return updatePixels(ng.get(), npal.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TileSheetEditor::TileSheetEditor(QString path, const studio::Context *ctx, QWidget *parent): QWidget(parent) {
|
TileSheetEditor::TileSheetEditor(QString path, const studio::Context *ctx, QWidget *parent): QWidget(parent) {
|
||||||
m_ctx = ctx;
|
m_ctx = ctx;
|
||||||
@ -80,6 +124,7 @@ TileSheetEditor::TileSheetEditor(QString path, const studio::Context *ctx, QWidg
|
|||||||
canvas->rootContext()->setContextProperty("sheetData", &m_sheetData);
|
canvas->rootContext()->setContextProperty("sheetData", &m_sheetData);
|
||||||
canvas->setSource(QUrl::fromLocalFile(":/qml/TileSheetEditor.qml"));
|
canvas->setSource(QUrl::fromLocalFile(":/qml/TileSheetEditor.qml"));
|
||||||
canvas->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
canvas->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||||
|
setColorTable(m_sheetData.palette());
|
||||||
restoreState();
|
restoreState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,23 +137,48 @@ QWidget *TileSheetEditor::setupColorPicker(QWidget *parent) {
|
|||||||
auto lyt = new QVBoxLayout(colorPicker);
|
auto lyt = new QVBoxLayout(colorPicker);
|
||||||
m_colorPicker.palette = new QComboBox(colorPicker);
|
m_colorPicker.palette = new QComboBox(colorPicker);
|
||||||
m_colorPicker.colorTable = new QTableWidget(colorPicker);
|
m_colorPicker.colorTable = new QTableWidget(colorPicker);
|
||||||
|
m_colorPicker.colorTable->setColumnCount(2);
|
||||||
|
m_colorPicker.colorTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
m_colorPicker.colorTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
m_colorPicker.colorTable->setHorizontalHeaderLabels(QStringList() << tr("Hex Code") << tr("Color"));
|
||||||
|
m_colorPicker.colorTable->horizontalHeader()->setStretchLastSection(true);
|
||||||
|
m_colorPicker.colorTable->verticalHeader()->hide();
|
||||||
|
connect(m_colorPicker.colorTable, &QTableWidget::itemSelectionChanged, this, &TileSheetEditor::colorSelected);
|
||||||
lyt->addWidget(m_colorPicker.palette);
|
lyt->addWidget(m_colorPicker.palette);
|
||||||
lyt->addWidget(m_colorPicker.colorTable);
|
lyt->addWidget(m_colorPicker.colorTable);
|
||||||
return colorPicker;
|
return colorPicker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileSheetEditor::setColorTable(QStringList hexColors) {
|
||||||
|
auto tbl = m_colorPicker.colorTable;
|
||||||
|
tbl->setRowCount(hexColors.size());
|
||||||
|
for (int i = 0; i < hexColors.size(); i++) {
|
||||||
|
auto hexCode = new QTableWidgetItem;
|
||||||
|
hexCode->setText(hexColors[i]);
|
||||||
|
hexCode->setFont(QFont("monospace"));
|
||||||
|
tbl->setItem(i, 0, hexCode);
|
||||||
|
auto color = new QTableWidgetItem;
|
||||||
|
color->setBackground(QColor(hexColors[i]));
|
||||||
|
tbl->setItem(i, 1, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TileSheetEditor::saveState() {
|
void TileSheetEditor::saveState() {
|
||||||
QSettings settings(m_ctx->orgName, PluginName);
|
QSettings settings(m_ctx->orgName, PluginName);
|
||||||
settings.beginGroup("TileSheetEditor/state");
|
settings.beginGroup("TileSheetEditor");
|
||||||
settings.setValue("m_splitter/state", m_splitter->saveState());
|
settings.setValue("m_splitter/state", m_splitter->saveState());
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditor::restoreState() {
|
void TileSheetEditor::restoreState() {
|
||||||
QSettings settings(m_ctx->orgName, PluginName);
|
QSettings settings(m_ctx->orgName, PluginName);
|
||||||
settings.beginGroup("TileSheetEditor/state");
|
settings.beginGroup("TileSheetEditor");
|
||||||
m_splitter->restoreState(settings.value("m_splitter/state", m_splitter->saveState()).toByteArray());
|
m_splitter->restoreState(settings.value("m_splitter/state", m_splitter->saveState()).toByteArray());
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TileSheetEditor::colorSelected() {
|
||||||
|
m_sheetData.setSelectedColor(m_colorPicker.colorTable->currentRow());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QStringView>
|
#include <QStringView>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
|
#include <QVariant>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <nostalgia/core/gfx.hpp>
|
#include <nostalgia/core/gfx.hpp>
|
||||||
@ -21,20 +22,42 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
class SheetData: public QObject {
|
class SheetData: public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
|
||||||
|
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList m_palette;
|
QStringList m_palette;
|
||||||
QVector<uint8_t> m_pixels;
|
QVector<uint8_t> m_pixels;
|
||||||
|
int m_columns = 2;
|
||||||
|
int m_rows = 2;
|
||||||
|
int m_selectedColor = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE QString pixel(int index);
|
Q_INVOKABLE QString pixel(int index);
|
||||||
|
|
||||||
void updatePixels(const NostalgiaGraphic *ng, const NostalgiaPalette *npal);
|
Q_INVOKABLE void updatePixels(QVariantList pixels);
|
||||||
|
|
||||||
|
int columns();
|
||||||
|
|
||||||
|
void setColumns(int columns);
|
||||||
|
|
||||||
|
int rows();
|
||||||
|
|
||||||
|
void setRows(int rows);
|
||||||
|
|
||||||
|
QStringList palette();
|
||||||
|
|
||||||
void updatePixels(const studio::Context *ctx, QString ngPath, QString palPath = "");
|
void updatePixels(const studio::Context *ctx, QString ngPath, QString palPath = "");
|
||||||
|
|
||||||
|
void setSelectedColor(int index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updatePixels(const NostalgiaGraphic *ng, const NostalgiaPalette *npal);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void refreshTileSheet();
|
void columnsChanged();
|
||||||
|
|
||||||
|
void rowsChanged();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,10 +82,15 @@ class TileSheetEditor: public QWidget {
|
|||||||
private:
|
private:
|
||||||
QWidget *setupColorPicker(QWidget *widget);
|
QWidget *setupColorPicker(QWidget *widget);
|
||||||
|
|
||||||
|
void setColorTable(QStringList hexColors);
|
||||||
|
|
||||||
void saveState();
|
void saveState();
|
||||||
|
|
||||||
void restoreState();
|
void restoreState();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void colorSelected();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user