Added biome color editor

This commit is contained in:
Cubitect 2022-04-23 22:45:21 +02:00
parent 54a4143f82
commit 087c394331
14 changed files with 504 additions and 12 deletions

@ -1 +1 @@
Subproject commit 0933804f15f4de107f0a1703f508521625292f87
Subproject commit 270ed5162bd6ed31287688955311ce8e7928737a

View File

@ -36,6 +36,7 @@ CONFIG += static
SOURCES += \
src/aboutdialog.cpp \
src/biomecolordialog.cpp \
src/collapsible.cpp \
src/conditiondialog.cpp \
src/configdialog.cpp \
@ -62,6 +63,7 @@ HEADERS += \
$$CUPATH/layers.h \
$$CUPATH/util.h \
src/aboutdialog.h \
src/biomecolordialog.h \
src/collapsible.h \
src/conditiondialog.h \
src/configdialog.h \
@ -86,6 +88,7 @@ HEADERS += \
FORMS += \
src/aboutdialog.ui \
src/biomecolordialog.ui \
src/conditiondialog.ui \
src/configdialog.ui \
src/extgendialog.ui \

View File

@ -6,7 +6,7 @@
#define VERS_MAJOR 2
#define VERS_MINOR 2
#define VERS_PATCH -1 // negative patch number designates a development version
#define VERS_PATCH -2 // negative patch number designates a development version
// returns +1 if newer, -1 if older and 0 if equal
inline int cmpVers(int major, int minor, int patch)

303
src/biomecolordialog.cpp Normal file
View File

@ -0,0 +1,303 @@
#include "biomecolordialog.h"
#include "ui_biomecolordialog.h"
#include "mainwindow.h"
#include "cutil.h"
#include <QPixmap>
#include <QPainter>
#include <QPainterPath>
#include <QPen>
#include <QIcon>
#include <QPushButton>
#include <QColorDialog>
#include <QInputDialog>
#include <QStandardPaths>
#include <QFile>
#include <QTextStream>
#include <QDirIterator>
#define DIM_DIVIDER 6
static QIcon getColorIcon(const QColor& col)
{
QPixmap pixmap(14,14);
pixmap.fill(QColor(0,0,0,0));
QPainter p(&pixmap);
p.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(QRectF(1, 1, 12, 12), 3, 3);
QPen pen(Qt::black, 1);
p.setPen(pen);
p.fillPath(path, col);
p.drawPath(path);
return QIcon(pixmap);
}
BiomeColorDialog::BiomeColorDialog(MainWindow *parent, QString initrc)
: QDialog(parent)
, ui(new Ui::BiomeColorDialog)
, parent(parent)
, modified()
{
ui->setupUi(this);
ui->buttonOk->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
memset(buttons, 0, sizeof(buttons));
memcpy(colors, biomeColors, sizeof(colors));
unsigned char coldefault[256][3];
initBiomeColors(coldefault);
QPushButton *button;
button = new QPushButton(QIcon(), tr("All to default"), this);
connect(button, &QPushButton::clicked, this, &BiomeColorDialog::onAllToDefault);
ui->gridLayout->addWidget(button, 0, 1);
button = new QPushButton(QIcon(), tr("All to dimmed"), this);
connect(button, &QPushButton::clicked, this, &BiomeColorDialog::onAllToDimmed);
ui->gridLayout->addWidget(button, 0, 2);
for (int i = 0; i < 256; i++)
{
const char *bname = biome2str(MC_NEWEST, i);
if (!bname)
continue;
QColor col;
col = QColor(colors[i][0], colors[i][1], colors[i][2]);
buttons[i] = button = new QPushButton(getColorIcon(col), bname, this);
connect(button, &QPushButton::clicked, [=]() { this->editBiomeColor(i); });
ui->gridLayout->addWidget(button, i+1, 0);
col = QColor(coldefault[i][0], coldefault[i][1], coldefault[i][2]);
button = new QPushButton(getColorIcon(col), tr("Default reset"), this);
connect(button, &QPushButton::clicked, [=]() { this->setBiomeColor(i, col); });
ui->gridLayout->addWidget(button, i+1, 1);
col = QColor(coldefault[i][0] / DIM_DIVIDER, coldefault[i][1] / DIM_DIVIDER, coldefault[i][2] / DIM_DIVIDER);
button = new QPushButton(getColorIcon(col), tr("Dimmed reset"), this);
connect(button, &QPushButton::clicked, [=]() { this->setBiomeColor(i, col); });
ui->gridLayout->addWidget(button, i+1, 2);
}
QString dir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
QDirIterator it(dir, QDirIterator::NoIteratorFlags);
while (it.hasNext())
{
QString rc = it.next();
if (!rc.endsWith(".colormap"))
continue;
QFile file(rc);
if (!file.open(QIODevice::ReadOnly))
continue;
QTextStream stream(&file);
QString line = stream.readLine();
if (line.length() < 2 || !line.startsWith(";"))
continue;
ui->comboColormaps->addItem(line.mid(1).trimmed(), rc);
}
ui->comboColormaps->model()->sort(0, Qt::AscendingOrder);
ui->comboColormaps->insertItem(0, tr("[default]"));
int index = 0;
for (int i = 0; i < ui->comboColormaps->count(); i++)
{
QString itemrc = qvariant_cast<QString>(ui->comboColormaps->itemData(i));
if (initrc == itemrc)
{
index = i;
break;
}
}
ui->comboColormaps->setCurrentIndex(index);
}
BiomeColorDialog::~BiomeColorDialog()
{
delete ui;
}
/// Saves the current colormap as the given rc.
/// If the rc already corresponds to an item, the description
/// will be updated only if the new desc is non-empty.
int BiomeColorDialog::saveColormap(QString rc, QString desc)
{
if (rc.isEmpty())
return -1;
QFile file(rc);
if (!file.open(QIODevice::WriteOnly))
return -1;
int index = -1;
for (int i = 0; i < ui->comboColormaps->count(); i++)
{
QString itemrc = qvariant_cast<QString>(ui->comboColormaps->itemData(i));
if (rc == itemrc)
{
index = i;
if (desc.isEmpty())
desc = ui->comboColormaps->itemText(i);
break;
}
}
QTextStream stream(&file);
stream << ";" << desc << "\n";
for (int i = 0; i < 256; i++)
{
const char *bname = biome2str(MC_NEWEST, i);
if (!bname)
continue;
stream << bname << " " << colors[i][0] << " " << colors[i][1] << " " << colors[i][2] << "\n";
}
modified = false;
if (index > 0)
{
ui->comboColormaps->setItemText(index, desc);
}
else
{
index = ui->comboColormaps->count();
ui->comboColormaps->addItem(desc, rc);
}
return index;
}
void BiomeColorDialog::setBiomeColor(int id, const QColor &col)
{
buttons[id]->setIcon(getColorIcon(col));
colors[id][0] = col.red();
colors[id][1] = col.green();
colors[id][2] = col.blue();
modified = true;
}
void BiomeColorDialog::editBiomeColor(int id)
{
QColor col = QColor(colors[id][0], colors[id][1], colors[id][2]);
QColorDialog *dialog = new QColorDialog(col, this);
//dialog->setOption(QColorDialog::DontUseNativeDialog, true);
if (dialog->exec())
{
setBiomeColor(id, dialog->selectedColor());
}
}
void BiomeColorDialog::on_comboColormaps_currentIndexChanged(int index)
{
ui->buttonRemove->setEnabled(index != 0);
if (modified)
{
if (activerc.isEmpty())
on_buttonSaveAs_clicked();
else
saveColormap(activerc, "");
}
activerc = qvariant_cast<QString>(ui->comboColormaps->currentData());
QFile file(activerc);
if (!activerc.isEmpty() && file.open(QIODevice::ReadOnly))
{
char buf[32*1024];
qint64 siz = file.read(buf, sizeof(buf)-1);
file.close();
if (siz >= 0)
{
buf[siz] = 0;
initBiomeColors(colors);
parseBiomeColors(colors, buf);
}
}
else
{
initBiomeColors(colors);
}
for (int i = 0; i < 256; i++)
{
if (buttons[i])
{
QColor col(colors[i][0], colors[i][1], colors[i][2]);
buttons[i]->setIcon(getColorIcon(col));
}
}
}
void BiomeColorDialog::on_buttonSaveAs_clicked()
{
QString rc;
int n;
QString path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
for (n = 1; n < 1000; n++)
{
rc = path + "/" + QString::number(n) + ".colormap";
if (!QFile::exists(rc))
break;
}
bool ok;
QString desc = QInputDialog::getText(
this, tr("Save biome colors as..."),
tr("Biome colors:"), QLineEdit::Normal,
QString("Colormap#%1").arg(n), &ok);
if (!ok || desc.isEmpty())
return;
int idx = saveColormap(rc, desc);
ui->comboColormaps->setCurrentIndex(idx);
activerc = rc;
}
void BiomeColorDialog::on_buttonRemove_clicked()
{
QString rc = qvariant_cast<QString>(ui->comboColormaps->currentData());
if (!rc.isEmpty())
{
modified = false; // discard changes
ui->comboColormaps->removeItem(ui->comboColormaps->currentIndex());
QFile file(rc);
file.remove();
}
}
void BiomeColorDialog::on_buttonOk_clicked()
{
on_comboColormaps_currentIndexChanged(ui->comboColormaps->currentIndex());
parent->setBiomeColorRc(activerc);
accept();
}
void BiomeColorDialog::onAllToDefault()
{
initBiomeColors(colors);
for (int i = 0; i < 256; i++)
{
if (buttons[i])
{
QColor col(colors[i][0], colors[i][1], colors[i][2]);
buttons[i]->setIcon(getColorIcon(col));
}
}
modified = true;
}
void BiomeColorDialog::onAllToDimmed()
{
initBiomeColors(colors);
for (int i = 0; i < 256; i++)
{
colors[i][0] /= DIM_DIVIDER;
colors[i][1] /= DIM_DIVIDER;
colors[i][2] /= DIM_DIVIDER;
if (buttons[i])
{
QColor col(colors[i][0], colors[i][1], colors[i][2]);
buttons[i]->setIcon(getColorIcon(col));
}
}
modified = true;
}

44
src/biomecolordialog.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef BIOMECOLORDIALOG_H
#define BIOMECOLORDIALOG_H
#include <QDialog>
namespace Ui {
class BiomeColorDialog;
}
class MainWindow;
class BiomeColorDialog : public QDialog
{
Q_OBJECT
public:
explicit BiomeColorDialog(MainWindow *parent, QString initrc);
~BiomeColorDialog();
int saveColormap(QString rc, QString desc);
public slots:
void setBiomeColor(int id, const QColor &col);
void editBiomeColor(int id);
private slots:
void on_comboColormaps_currentIndexChanged(int index);
void on_buttonSaveAs_clicked();
void on_buttonRemove_clicked();
void on_buttonOk_clicked();
void onAllToDefault();
void onAllToDimmed();
private:
Ui::BiomeColorDialog *ui;
MainWindow *parent;
QPushButton *buttons[256];
unsigned char colors[256][3];
QString activerc;
bool modified;
};
#endif // BIOMECOLORDIALOG_H

87
src/biomecolordialog.ui Normal file
View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BiomeColorDialog</class>
<widget class="QDialog" name="BiomeColorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Biome Color Editor</string>
</property>
<property name="windowIcon">
<iconset resource="../rc/icons.qrc">
<normaloff>:/icons/map.png</normaloff>:/icons/map.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="comboColormaps"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Biome color map:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonSaveAs">
<property name="text">
<string>Save as...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonOk">
<property name="text">
<string>Ok</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="3">
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>562</width>
<height>521</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">text-align:left;</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../rc/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -35,6 +35,7 @@ inline const char* struct2str(int stype)
case Bastion: return "bastion";
case End_City: return "end_city";
case End_Gateway: return "end_gateway";
case Ancient_City: return "ancient_city";
}
return "?";
}

View File

@ -7,6 +7,7 @@
#include "aboutdialog.h"
#include "conditiondialog.h"
#include "extgendialog.h"
#include "biomecolordialog.h"
#if WITH_UPDATER
#include "updater.h"
@ -344,6 +345,12 @@ int MainWindow::getDim()
return 0;
}
void MainWindow::setBiomeColorRc(QString rc)
{
config.biomeColorPath = rc;
onBiomeColorChange();
}
void MainWindow::saveSettings()
{
QSettings settings("cubiomes-viewer", "cubiomes-viewer");
@ -837,7 +844,7 @@ void MainWindow::on_actionPreferences_triggered()
void MainWindow::onBiomeColorChange()
{
QFile file(config.biomeColorPath);
if (file.open(QIODevice::ReadOnly))
if (!config.biomeColorPath.isEmpty() && file.open(QIODevice::ReadOnly))
{
char buf[32*1024];
qint64 siz = file.read(buf, sizeof(buf)-1);
@ -853,7 +860,7 @@ void MainWindow::onBiomeColorChange()
{
initBiomeColors(biomeColors);
}
ui->mapView->refresh();
ui->mapView->refreshBiomeColors();
}
void MainWindow::on_actionGo_to_triggered()
@ -878,6 +885,12 @@ void MainWindow::on_actionOpen_shadow_seed_triggered()
}
}
void MainWindow::on_actionBiome_colors_triggered()
{
BiomeColorDialog *dialog = new BiomeColorDialog(this, config.biomeColorPath);
dialog->show();
}
void MainWindow::on_actionPresetLoad_triggered()
{
WorldInfo wi;

View File

@ -50,6 +50,7 @@ public:
bool setSeed(WorldInfo wi, int dim = INT_MAX);
int getDim();
MapView *getMapView();
void setBiomeColorRc(QString rc);
protected:
@ -77,6 +78,7 @@ private slots:
void on_actionGo_to_triggered();
void on_actionScan_seed_for_Quad_Huts_triggered();
void on_actionOpen_shadow_seed_triggered();
void on_actionBiome_colors_triggered();
void on_actionPresetLoad_triggered();
void on_actionExamples_triggered();
void on_actionAbout_triggered();

View File

@ -773,6 +773,7 @@ QToolButton:checked {
<string>Map</string>
</property>
<addaction name="actionGo_to"/>
<addaction name="actionBiome_colors"/>
<addaction name="actionScan_seed_for_Quad_Huts"/>
<addaction name="actionOpen_shadow_seed"/>
</widget>
@ -903,6 +904,11 @@ QToolButton:checked {
<string>Load filter preset...</string>
</property>
</action>
<action name="actionBiome_colors">
<property name="text">
<string>Biome colors...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -135,6 +135,12 @@ void MapView::setConfig(const Config& c)
update(2);
}
void MapView::refreshBiomeColors()
{
if (world)
world->refreshBiomeColors();
}
void MapView::settingsToWorld()
{
if (!world)

View File

@ -44,6 +44,7 @@ public:
bool getShow(int stype) { return stype >= 0 && stype < STRUCT_NUM ? sshow[stype] : false; }
void setShow(int stype, bool v);
void setConfig(const Config& config);
void refreshBiomeColors();
void timeout();

View File

@ -14,7 +14,7 @@
Quad::Quad(const Level* l, int i, int j)
: wi(l->wi),dim(l->dim),g(&l->g),scale(l->scale)
, ti(i),tj(j),blocks(l->blocks),pixs(l->pixs),sopt(l->sopt)
, rgb(),img(),spos()
, biomes(),rgb(),img(),spos()
, done(),isdel(l->isdel)
, prio(),stopped()
{
@ -23,6 +23,7 @@ Quad::Quad(const Level* l, int i, int j)
Quad::~Quad()
{
if (biomes) free(biomes);
delete img;
delete spos;
delete [] rgb;
@ -104,6 +105,7 @@ void getStructs(std::vector<VarPos> *out, const StructureConfig sconf,
}
}
QMutex g_mutex(QMutex::NonRecursive);
void Quad::run()
{
@ -115,10 +117,10 @@ void Quad::run()
int y = (scale > 1) ? wi.y >> 2 : wi.y;
int x = ti*pixs, z = tj*pixs, w = pixs+SEAM_BUF, h = pixs+SEAM_BUF;
Range r = {scale, x, z, w, h, y, 1};
int *b = allocCache(g, r);
if (!b) return;
biomes = allocCache(g, r);
if (!biomes) return;
int err = genBiomes(g, b, r);
int err = genBiomes(g, biomes, r);
if (err)
{
fprintf(
@ -128,11 +130,15 @@ void Quad::run()
mc2str(g->mc), g->seed, g->dim,
x, z, w, h, scale);
for (int i = 0; i < w*h; i++)
b[i] = -1;
biomes[i] = -1;
}
// sync biomeColors
g_mutex.lock();
g_mutex.unlock();
rgb = new uchar[w*h * 3];
biomesToImage(rgb, biomeColors, b, w, h, 1, 1);
free(b);
biomesToImage(rgb, biomeColors, biomes, w, h, 1, 1);
img = new QImage(rgb, w, h, 3*w, QImage::Format_RGB888);
}
else
@ -469,6 +475,23 @@ int QWorld::getBiome(Pos p)
return id;
}
void QWorld::refreshBiomeColors()
{
g_mutex.lock();
for (Level& l : lvb)
{
for (Quad *q : l.cells)
{
QImage *img = q->img;
if (!img)
continue;
biomesToImage(q->rgb, biomeColors, q->biomes, img->width(), img->height(), 1, 1);
}
}
g_mutex.unlock();
}
void QWorld::cleancache(std::vector<Quad*>& cache, unsigned int maxsize)
{
size_t n = cache.size();
@ -910,7 +933,7 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
}
int pixs = lvb[0].pixs + SEAM_BUF;
unsigned int cachesize = memlimit / pixs / pixs / 3;
unsigned int cachesize = memlimit / pixs / pixs / 7; // sizeof(RGB) + sizeof(biome_id)
cleancache(cachedbiomes, cachesize);
cleancache(cachedstruct, cachesize);

View File

@ -160,6 +160,7 @@ public:
int pixs;
int sopt;
int *biomes;
uchar *rgb;
// img and spos act as an atomic gate (with NULL or non-NULL indicating available results)
@ -217,6 +218,8 @@ struct QWorld
int getBiome(Pos p);
void refreshBiomeColors();
WorldInfo wi;
int dim;
Generator g;