添加导出PNG的功能
parent
fbc08b30fb
commit
dad2c1fa59
|
@ -162,6 +162,7 @@
|
||||||
<ClCompile Include="src\Renderer\Painting\Painting.cpp" />
|
<ClCompile Include="src\Renderer\Painting\Painting.cpp" />
|
||||||
<ClCompile Include="src\Renderer\PaintingMesh.cpp" />
|
<ClCompile Include="src\Renderer\PaintingMesh.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Preview\ElementRenderer.cpp" />
|
<ClCompile Include="src\Renderer\Preview\ElementRenderer.cpp" />
|
||||||
|
<ClCompile Include="src\Renderer\Preview\PaintingRenderer.cpp" />
|
||||||
<ClCompile Include="src\Renderer\RendererGLWidget.cpp" />
|
<ClCompile Include="src\Renderer\RendererGLWidget.cpp" />
|
||||||
<ClCompile Include="src\Renderer\RendererWidget.cpp" />
|
<ClCompile Include="src\Renderer\RendererWidget.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Painting\ShortCutTree.cpp" />
|
<ClCompile Include="src\Renderer\Painting\ShortCutTree.cpp" />
|
||||||
|
@ -253,6 +254,7 @@
|
||||||
<ClInclude Include="src\Renderer\Painting\MaterialStyleStroke.h" />
|
<ClInclude Include="src\Renderer\Painting\MaterialStyleStroke.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\Painting.h" />
|
<ClInclude Include="src\Renderer\Painting\Painting.h" />
|
||||||
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h" />
|
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h" />
|
||||||
|
<ClInclude Include="src\Renderer\Preview\PaintingRenderer.h" />
|
||||||
<ClInclude Include="src\Renderer\VirtualTextureManager.h" />
|
<ClInclude Include="src\Renderer\VirtualTextureManager.h" />
|
||||||
<ClInclude Include="src\SvgParser.h" />
|
<ClInclude Include="src\SvgParser.h" />
|
||||||
<QtMoc Include="src\NavigationBarWidget.h" />
|
<QtMoc Include="src\NavigationBarWidget.h" />
|
||||||
|
|
|
@ -282,6 +282,9 @@
|
||||||
<ClCompile Include="src\Editor\Properties\ProjectPropertyWidget.cpp">
|
<ClCompile Include="src\Editor\Properties\ProjectPropertyWidget.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Renderer\Preview\PaintingRenderer.cpp">
|
||||||
|
<Filter>Source Files\Renderer\Preview</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
||||||
|
@ -570,6 +573,9 @@
|
||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Renderer\Preview\PaintingRenderer.h">
|
||||||
|
<Filter>Header Files\Renderer\Preview</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtRcc Include="res\MainWindow.qrc">
|
<QtRcc Include="res\MainWindow.qrc">
|
||||||
|
|
|
@ -69,10 +69,12 @@ void EditorWidget::initFileMenu()
|
||||||
auto* actionOpen = new QAction(QStringLiteral("´ò¿ª"), fileMenuButton);
|
auto* actionOpen = new QAction(QStringLiteral("´ò¿ª"), fileMenuButton);
|
||||||
auto* actionSave = new QAction(QStringLiteral("±£´æ"), fileMenuButton);
|
auto* actionSave = new QAction(QStringLiteral("±£´æ"), fileMenuButton);
|
||||||
auto* actionSaveAs = new QAction(QStringLiteral("Áí´æΪ"), fileMenuButton);
|
auto* actionSaveAs = new QAction(QStringLiteral("Áí´æΪ"), fileMenuButton);
|
||||||
|
auto* actionExport = new QAction(QStringLiteral("µ¼³ö"), fileMenuButton);
|
||||||
fileMenuButton->addMenuAction(actionCreate);
|
fileMenuButton->addMenuAction(actionCreate);
|
||||||
fileMenuButton->addMenuAction(actionOpen);
|
fileMenuButton->addMenuAction(actionOpen);
|
||||||
fileMenuButton->addMenuAction(actionSave);
|
fileMenuButton->addMenuAction(actionSave);
|
||||||
fileMenuButton->addMenuAction(actionSaveAs);
|
fileMenuButton->addMenuAction(actionSaveAs);
|
||||||
|
fileMenuButton->addMenuAction(actionExport);
|
||||||
connect(actionCreate, &QAction::triggered, [this] {
|
connect(actionCreate, &QAction::triggered, [this] {
|
||||||
static int count = 0;
|
static int count = 0;
|
||||||
const int prevCount = this->tabWidget->count();
|
const int prevCount = this->tabWidget->count();
|
||||||
|
@ -108,6 +110,13 @@ void EditorWidget::initFileMenu()
|
||||||
item->saveAs(fileName);
|
item->saveAs(fileName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
connect(actionExport, &QAction::triggered, this, [this] {
|
||||||
|
auto* item = dynamic_cast<EditorWidgetItem*>(this->tabWidget->currentWidget());
|
||||||
|
if (item != nullptr)
|
||||||
|
{
|
||||||
|
item->exportAs();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidget::initProjectMenu()
|
void EditorWidget::initProjectMenu()
|
||||||
|
|
|
@ -1,126 +1,131 @@
|
||||||
#include "EditorWidgetItem.h"
|
#include "EditorWidgetItem.h"
|
||||||
#include "EditorWidget.h"
|
#include "EditorWidget.h"
|
||||||
#include "DataManager/ProjectDataManager.h"
|
#include "DataManager/ProjectDataManager.h"
|
||||||
|
#include "../Renderer/Preview/PaintingRenderer.h"
|
||||||
|
#include "util/PaintingUtil.h"
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(parent)
|
EditorWidgetItem::EditorWidgetItem(QString filePath, QWidget* parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
QImage x;
|
QImage x;
|
||||||
this->parent = parent;
|
this->parent = parent;
|
||||||
displayLayer = nullptr;
|
displayLayer = nullptr;
|
||||||
displayElement = nullptr;
|
displayElement = nullptr;
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
previewWindow = ui.Preview;
|
previewWindow = ui.Preview;
|
||||||
treeWidget = ui.LayerTree;
|
treeWidget = ui.LayerTree;
|
||||||
this->filePath = filePath;
|
this->filePath = filePath;
|
||||||
elementInfoDisplayWidget = ui.ElementDisplay;
|
elementInfoDisplayWidget = ui.ElementDisplay;
|
||||||
layerInfoDisplayWidget = ui.LayerDisplay;
|
layerInfoDisplayWidget = ui.LayerDisplay;
|
||||||
elementInfoDisplayWidget->enableEdit();
|
elementInfoDisplayWidget->enableEdit();
|
||||||
qDebug() << layerInfoDisplayWidget;
|
qDebug() << layerInfoDisplayWidget;
|
||||||
qDebug() << elementInfoDisplayWidget;
|
qDebug() << elementInfoDisplayWidget;
|
||||||
auto centralRefresh = [this]() {
|
auto centralRefresh = [this]() {
|
||||||
layerInfoDisplayWidget->refresh();
|
layerInfoDisplayWidget->refresh();
|
||||||
treeWidget->refresh();
|
treeWidget->refresh();
|
||||||
previewWindow->refresh();
|
previewWindow->refresh();
|
||||||
elementInfoDisplayWidget->lazyRefresh();
|
elementInfoDisplayWidget->lazyRefresh();
|
||||||
};
|
};
|
||||||
connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh);
|
connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh);
|
||||||
connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh);
|
connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh);
|
||||||
connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh);
|
connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh);
|
||||||
connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh);
|
connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh);
|
||||||
connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex);
|
connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex);
|
||||||
connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged);
|
connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged);
|
||||||
//connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
|
//connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
|
||||||
// connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
|
// connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
|
||||||
connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange);
|
connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange);
|
||||||
// connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this,
|
// connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this,
|
||||||
// &EditorWidgetItem::triggerRefreshPreview);
|
// &EditorWidgetItem::triggerRefreshPreview);
|
||||||
// connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
|
// connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
|
||||||
// &EditorWidgetItem::triggerRefreshPreview);
|
// &EditorWidgetItem::triggerRefreshPreview);
|
||||||
//connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
|
//connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
|
||||||
// connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh);
|
// connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh);
|
||||||
// &EditorWidget::triggerRefreshPreview);
|
// &EditorWidget::triggerRefreshPreview);
|
||||||
// test
|
// test
|
||||||
QFile settingFile;
|
QFile settingFile;
|
||||||
//settingFile.setFileName("../data.json");
|
//settingFile.setFileName("../data.json");
|
||||||
settingFile.setFileName(filePath);
|
settingFile.setFileName(filePath);
|
||||||
settingFile.open(QFile::ReadOnly);
|
settingFile.open(QFile::ReadOnly);
|
||||||
QByteArray setting = settingFile.readAll().trimmed();
|
QByteArray setting = settingFile.readAll().trimmed();
|
||||||
QJsonParseError jError;
|
QJsonParseError jError;
|
||||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(setting, &jError));
|
QJsonDocument jsonDoc(QJsonDocument::fromJson(setting, &jError));
|
||||||
qDebug() << jsonDoc.object().value("height").toDouble();
|
qDebug() << jsonDoc.object().value("height").toDouble();
|
||||||
qDebug() << jError.errorString();
|
qDebug() << jError.errorString();
|
||||||
ProjectData data;
|
ProjectData data;
|
||||||
data.fileHome = QFileInfo(filePath).absolutePath();
|
data.fileHome = QFileInfo(filePath).absolutePath();
|
||||||
data.width = jsonDoc.object().value("height").toInt();
|
data.width = jsonDoc.object().value("height").toInt();
|
||||||
data.height = jsonDoc.object().value("width").toInt();
|
data.height = jsonDoc.object().value("width").toInt();
|
||||||
data.zoomX = 1.0;
|
data.zoomX = 1.0;
|
||||||
data.zoomY = 1.0;
|
data.zoomY = 1.0;
|
||||||
data.item = this;
|
data.item = this;
|
||||||
ProjectDataManager::Instance()->addProjectData(data);
|
ProjectDataManager::Instance()->addProjectData(data);
|
||||||
// end test
|
// end test
|
||||||
QJsonObject source = jsonDoc.object();
|
QJsonObject source = jsonDoc.object();
|
||||||
elementManager = new ElementManager(source, QFileInfo(filePath).absolutePath());
|
elementManager = new ElementManager(source, QFileInfo(filePath).absolutePath());
|
||||||
layerManager = new LayerManager(source, elementManager);
|
layerManager = new LayerManager(source, elementManager);
|
||||||
elementInfoDisplayWidget->setElementManager(elementManager);
|
elementInfoDisplayWidget->setElementManager(elementManager);
|
||||||
treeWidget->elementManager = elementManager;
|
treeWidget->elementManager = elementManager;
|
||||||
//qDebug() << layerManager->toJson();
|
//qDebug() << layerManager->toJson();
|
||||||
previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toInt(),jsonDoc.object().value("height").toInt()));
|
previewWindow->initialize(layerManager, QSize(jsonDoc.object().value("width").toInt(), jsonDoc.object().value("height").toInt()));
|
||||||
if (source.contains("metallic"))
|
if (source.contains("metallic"))
|
||||||
previewWindow->canvasMetallic = jsonDoc.object().value("metallic").toDouble();
|
previewWindow->canvasMetallic = jsonDoc.object().value("metallic").toDouble();
|
||||||
else
|
else
|
||||||
previewWindow->canvasMetallic = 0;
|
previewWindow->canvasMetallic = 0;
|
||||||
if (source.contains("roughness"))
|
if (source.contains("roughness"))
|
||||||
previewWindow->canvasRoughness = jsonDoc.object().value("roughness").toDouble();
|
previewWindow->canvasRoughness = jsonDoc.object().value("roughness").toDouble();
|
||||||
else
|
else
|
||||||
previewWindow->canvasRoughness = 0.5;
|
previewWindow->canvasRoughness = 0.5;
|
||||||
|
|
||||||
|
|
||||||
if (layerManager->getRoot() != nullptr)
|
if (layerManager->getRoot() != nullptr)
|
||||||
{
|
{
|
||||||
treeWidget->root = layerManager->getRoot();
|
treeWidget->root = layerManager->getRoot();
|
||||||
treeWidget->refresh();
|
treeWidget->refresh();
|
||||||
treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem());
|
treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem());
|
||||||
}
|
}
|
||||||
this->backgroundColor = source.value("background-color").toVariant().value<QColor>();
|
this->backgroundColor = source.value("background-color").toVariant().value<QColor>();
|
||||||
this->projectName = source.value("project-name").toString();
|
this->projectName = source.value("project-name").toString();
|
||||||
qDebug() << this->backgroundColor;
|
qDebug() << this->backgroundColor;
|
||||||
qDebug() << this->projectName;
|
qDebug() << this->projectName;
|
||||||
elementInfoDisplayWidget->refresh();
|
elementInfoDisplayWidget->refresh();
|
||||||
QTimer::singleShot(300, this, [this, centralRefresh]() {
|
QTimer::singleShot(300, this, [this, centralRefresh]() {
|
||||||
handleBackgroundColorChange(this->backgroundColor);
|
handleBackgroundColorChange(this->backgroundColor);
|
||||||
handleProjectNameChange(this->projectName);
|
handleProjectNameChange(this->projectName);
|
||||||
centralRefresh();
|
centralRefresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorWidgetItem::~EditorWidgetItem()
|
EditorWidgetItem::~EditorWidgetItem()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::paintEvent(QPaintEvent *event)
|
void EditorWidgetItem::paintEvent(QPaintEvent* event)
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
// 设置画刷的颜色为灰色,并填充整个窗口区域
|
// 设置画刷的颜色为灰色,并填充整个窗口区域
|
||||||
painter.setBrush(Qt::gray);
|
painter.setBrush(Qt::gray);
|
||||||
painter.drawRect(this->rect());
|
painter.drawRect(this->rect());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::onLayerChange(LayerWrapper *layer)
|
void EditorWidgetItem::onLayerChange(LayerWrapper* layer)
|
||||||
{
|
{
|
||||||
displayLayer = layer;
|
displayLayer = layer;
|
||||||
// TODO : notify InfoDisplayWidget and update
|
// TODO : notify InfoDisplayWidget and update
|
||||||
ui.LayerDisplay->setLayer(layer);
|
ui.LayerDisplay->setLayer(layer);
|
||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::triggerRefreshPreview()
|
void EditorWidgetItem::triggerRefreshPreview()
|
||||||
{
|
{
|
||||||
previewWindow->update();
|
previewWindow->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::save() const
|
void EditorWidgetItem::save() const
|
||||||
|
@ -132,36 +137,103 @@ void EditorWidgetItem::saveAs(QString filePath) const
|
||||||
{
|
{
|
||||||
saveImpl(filePath);
|
saveImpl(filePath);
|
||||||
QString srcHome = QFileInfo(this->filePath).absolutePath();
|
QString srcHome = QFileInfo(this->filePath).absolutePath();
|
||||||
if (!QDir(QFileInfo(filePath).absolutePath() + "/svg").exists())
|
if (!QDir(QFileInfo(filePath).absolutePath() + "/svg").exists())
|
||||||
{
|
{
|
||||||
QDir().mkdir(QFileInfo(filePath).absolutePath() + "/svg");
|
QDir().mkdir(QFileInfo(filePath).absolutePath() + "/svg");
|
||||||
}
|
}
|
||||||
for (auto& ele : elementManager->elements)
|
for (auto& ele : elementManager->elements)
|
||||||
{
|
{
|
||||||
auto e = dynamic_cast<SimpleElement*>(ele);
|
auto e = dynamic_cast<SimpleElement*>(ele);
|
||||||
if (e != nullptr)
|
if (e != nullptr)
|
||||||
{
|
{
|
||||||
QString fileName = e->jsonSource["data"].toObject()["include"].toString();
|
QString fileName = e->jsonSource["data"].toObject()["include"].toString();
|
||||||
QString src = srcHome + fileName;
|
QString src = srcHome + fileName;
|
||||||
QString dst = QFileInfo(filePath).absolutePath() + fileName;
|
QString dst = QFileInfo(filePath).absolutePath() + fileName;
|
||||||
QFile::copy(src, dst);
|
QFile::copy(src, dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorWidgetItem::exportAs()
|
||||||
|
{
|
||||||
|
const QString fileName = QFileDialog::getSaveFileName(this, QStringLiteral("导出"), QFileInfo(filePath).dir().filePath(projectName), QStringLiteral("PNG图像(*.png)"));
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QtMaterialTextField widthTextField;
|
||||||
|
QtMaterialTextField heightTextField;
|
||||||
|
QtMaterialTextField supersampleTextField;
|
||||||
|
widthTextField.setLabel(QStringLiteral("宽度(像素)"));
|
||||||
|
heightTextField.setLabel(QStringLiteral("高度(像素)"));
|
||||||
|
supersampleTextField.setLabel(QStringLiteral("超采样(倍)"));
|
||||||
|
|
||||||
|
class FixedIntValidator : public QIntValidator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit FixedIntValidator(QObject* parent = nullptr) : QIntValidator(parent) {}
|
||||||
|
explicit FixedIntValidator(int bottom, int top, QObject* parent = nullptr) : QIntValidator(
|
||||||
|
bottom, top, parent) {}
|
||||||
|
|
||||||
|
void fixup(QString& s) const override
|
||||||
|
{
|
||||||
|
s = QString::number(bottom());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
widthTextField.setValidator(new FixedIntValidator(1, std::numeric_limits<int>::max(), &widthTextField));
|
||||||
|
heightTextField.setValidator(new FixedIntValidator(1, std::numeric_limits<int>::max(), &heightTextField));
|
||||||
|
supersampleTextField.setValidator(new QDoubleValidator(0.125, 128, 3));
|
||||||
|
widthTextField.setText(QString::number(previewWindow->referSize.width()));
|
||||||
|
heightTextField.setText(QString::number(previewWindow->referSize.height()));
|
||||||
|
supersampleTextField.setText(QString::number(2));
|
||||||
|
|
||||||
|
connect(&widthTextField, &QLineEdit::textChanged, [&](const QString& string) {
|
||||||
|
heightTextField.setText(QString::number(previewWindow->referSize.height() * string.toInt() / (double)previewWindow->referSize.width()));
|
||||||
|
});
|
||||||
|
connect(&heightTextField, &QLineEdit::textChanged, [&](const QString& string) {
|
||||||
|
widthTextField.setText(QString::number(previewWindow->referSize.width() * string.toInt() / (double)previewWindow->referSize.height()));
|
||||||
|
});
|
||||||
|
|
||||||
|
QDialog* dialog = new QDialog(this);
|
||||||
|
dialog->setMinimumSize(QSize(200, 200));
|
||||||
|
dialog->setWindowTitle(QStringLiteral("导出"));
|
||||||
|
dialog->setWindowFlag(Qt::WindowContextHelpButtonHint, false);
|
||||||
|
auto layout = new QVBoxLayout(dialog);
|
||||||
|
dialog->setLayout(layout);
|
||||||
|
layout->addWidget(&widthTextField);
|
||||||
|
layout->addWidget(&heightTextField);
|
||||||
|
layout->addWidget(&supersampleTextField);
|
||||||
|
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);
|
||||||
|
buttonBox->button(QDialogButtonBox::Ok)->setText(QStringLiteral("确定"));
|
||||||
|
buttonBox->button(QDialogButtonBox::Cancel)->setText(QStringLiteral("取消"));
|
||||||
|
layout->addWidget(buttonBox);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, [&] {
|
||||||
|
dialog->setCursor(Qt::WaitCursor);
|
||||||
|
auto painting = PaintingUtil::transfromToPainting(this->filePath);
|
||||||
|
Renderer::PaintingRenderer::instance().exportPainting(fileName, painting, QSize(widthTextField.text().toInt(), heightTextField.text().toInt()), supersampleTextField.text().toFloat());
|
||||||
|
dialog->unsetCursor();
|
||||||
|
dialog->accept();
|
||||||
|
});
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, [&] {
|
||||||
|
dialog->close();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->exec();
|
||||||
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::saveImpl(QString filePath) const
|
void EditorWidgetItem::saveImpl(QString filePath) const
|
||||||
{
|
{
|
||||||
QJsonObject source1 = layerManager->toJson();
|
QJsonObject source1 = layerManager->toJson();
|
||||||
QJsonObject source2 = elementManager->toJson();
|
QJsonObject source2 = elementManager->toJson();
|
||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
json.insert("roughness", previewWindow->canvasRoughness);
|
json.insert("roughness", previewWindow->canvasRoughness);
|
||||||
json.insert("metallic", previewWindow->canvasMetallic);
|
json.insert("metallic", previewWindow->canvasMetallic);
|
||||||
json.insert("width", previewWindow->referSize.width());
|
json.insert("width", previewWindow->referSize.width());
|
||||||
json.insert("height", previewWindow->referSize.height());
|
json.insert("height", previewWindow->referSize.height());
|
||||||
json.insert("root-layer", source1.value("root-layer"));
|
json.insert("root-layer", source1.value("root-layer"));
|
||||||
json.insert("elements", source2.value("elements"));
|
json.insert("elements", source2.value("elements"));
|
||||||
json.insert("project-name", this->projectName);
|
json.insert("project-name", this->projectName);
|
||||||
json.insert("background-color", QJsonValue::fromVariant(QVariant::fromValue(this->backgroundColor)));
|
json.insert("background-color", QJsonValue::fromVariant(QVariant::fromValue(this->backgroundColor)));
|
||||||
QJsonDocument doc(json);
|
QJsonDocument doc(json);
|
||||||
QFile file(filePath);
|
QFile file(filePath);
|
||||||
|
@ -179,17 +251,17 @@ void EditorWidgetItem::handleBackgroundColorChange(const QColor& color)
|
||||||
void EditorWidgetItem::handleProjectNameChange(const QString& name)
|
void EditorWidgetItem::handleProjectNameChange(const QString& name)
|
||||||
{
|
{
|
||||||
this->projectName = name;
|
this->projectName = name;
|
||||||
auto parent = dynamic_cast<EditorWidget*>(this->parent);
|
auto parent = dynamic_cast<EditorWidget*>(this->parent);
|
||||||
qDebug() << name << " " << parent<<" "<<this;
|
qDebug() << name << " " << parent << " " << this;
|
||||||
if (parent != nullptr)
|
if (parent != nullptr)
|
||||||
{
|
{
|
||||||
parent->renameTab(this, name);
|
parent->renameTab(this, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::handleCanvasSizeChange(const QSize& size)
|
void EditorWidgetItem::handleCanvasSizeChange(const QSize& size)
|
||||||
{
|
{
|
||||||
previewWindow->resize(size);
|
previewWindow->resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorWidgetItem::handleCanvasRoughnessChange(const float& roughness)
|
void EditorWidgetItem::handleCanvasRoughnessChange(const float& roughness)
|
||||||
|
@ -204,7 +276,7 @@ void EditorWidgetItem::handleCanvasMetallicChange(const float& metallic)
|
||||||
|
|
||||||
QSize EditorWidgetItem::getCanvasReferSize() const
|
QSize EditorWidgetItem::getCanvasReferSize() const
|
||||||
{
|
{
|
||||||
return previewWindow->referSize;
|
return previewWindow->referSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
float EditorWidgetItem::getCanvasRoughness() const
|
float EditorWidgetItem::getCanvasRoughness() const
|
||||||
|
|
|
@ -32,7 +32,7 @@ class EditorWidgetItem : public QWidget
|
||||||
GraphicElement *displayElement;
|
GraphicElement *displayElement;
|
||||||
QWidget* parent;
|
QWidget* parent;
|
||||||
void saveImpl(QString filePath)const;
|
void saveImpl(QString filePath)const;
|
||||||
public:
|
public:
|
||||||
// PROJECT INFO
|
// PROJECT INFO
|
||||||
QString filePath;
|
QString filePath;
|
||||||
QString projectName;
|
QString projectName;
|
||||||
|
@ -43,7 +43,8 @@ public:
|
||||||
~EditorWidgetItem();
|
~EditorWidgetItem();
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
void save() const;
|
void save() const;
|
||||||
void saveAs(QString filePath)const;
|
void saveAs(QString filePath) const;
|
||||||
|
void exportAs();
|
||||||
void handleBackgroundColorChange(const QColor& color);
|
void handleBackgroundColorChange(const QColor& color);
|
||||||
void handleProjectNameChange(const QString& name);
|
void handleProjectNameChange(const QString& name);
|
||||||
void handleCanvasSizeChange(const QSize& size);
|
void handleCanvasSizeChange(const QSize& size);
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "PaintingRenderer.h"
|
||||||
|
#include <QOpenGLFramebufferObject>
|
||||||
|
|
||||||
|
Renderer::PaintingRenderer& Renderer::PaintingRenderer::instance()
|
||||||
|
{
|
||||||
|
static PaintingRenderer renderer;
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Renderer::PaintingRenderer::exportPainting(const QString& path, Painting& painting, const QSize& size, float supersampling)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(drawMutex);
|
||||||
|
draw.wait(lock, [&] {return drawFinished; });
|
||||||
|
drawFinished = false;
|
||||||
|
this->path = path;
|
||||||
|
this->painting = &painting;
|
||||||
|
this->size = size;
|
||||||
|
this->supersampling = supersampling;
|
||||||
|
needDraw = true;
|
||||||
|
draw.notify_all();
|
||||||
|
draw.wait(lock, [&] {return drawFinished; });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::PaintingRenderer::PaintingRenderer()
|
||||||
|
{
|
||||||
|
surface.create();
|
||||||
|
thread = std::jthread([&](std::stop_token stop) {
|
||||||
|
std::stop_callback cb(stop, [&] {
|
||||||
|
draw.notify_all();
|
||||||
|
});
|
||||||
|
|
||||||
|
QOpenGLContext context;
|
||||||
|
context.create();
|
||||||
|
context.makeCurrent(&surface);
|
||||||
|
|
||||||
|
auto gl = context.versionFunctions<QOpenGLFunctions_4_5_Core>();
|
||||||
|
shader = std::make_unique<QOpenGLShaderProgram>();
|
||||||
|
if (!shader->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/painting.comp"))
|
||||||
|
qDebug() << "ERROR: " << shader->log();
|
||||||
|
if (!shader->link())
|
||||||
|
qDebug() << "ERROR: " << shader->log();
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
while (!stop.stop_requested())
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(drawMutex);
|
||||||
|
draw.wait(lock, [&] {return needDraw || stop.stop_requested(); });
|
||||||
|
if (needDraw)
|
||||||
|
{
|
||||||
|
needDraw = false;
|
||||||
|
painting->generateBuffers(gl);
|
||||||
|
QSize renderSize = size * supersampling;
|
||||||
|
auto fbo = QOpenGLFramebufferObject(renderSize, QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D);
|
||||||
|
fbo.bind();
|
||||||
|
gl->glClearColor(0, 0, 0, 0);
|
||||||
|
gl->glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
fbo.release();
|
||||||
|
|
||||||
|
shader->bind();
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
gl->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting->buffers[i]);
|
||||||
|
gl->glBindBufferBase(GL_UNIFORM_BUFFER, 1, painting->buffers[6]);
|
||||||
|
gl->glUniform2i(gl->glGetUniformLocation(shader->programId(), "pixelOffset"), 0, 0);
|
||||||
|
gl->glBindImageTexture(0, fbo.texture(), 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
||||||
|
gl->glBindImageTexture(1, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
|
||||||
|
gl->glDispatchCompute((GLuint)ceil(renderSize.width() / 8.), (GLuint)ceil(renderSize.height() / 8.), 1);
|
||||||
|
shader->release();
|
||||||
|
auto image = fbo.toImage(true);
|
||||||
|
image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).save(path, "PNG", 100);
|
||||||
|
gl->glDeleteBuffers(7, painting->buffers.data());
|
||||||
|
drawFinished = true;
|
||||||
|
}
|
||||||
|
draw.notify_all();
|
||||||
|
}
|
||||||
|
context.doneCurrent();
|
||||||
|
});
|
||||||
|
|
||||||
|
while (!initialized)
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QOpenGLWidget>
|
||||||
|
#include <QOpenGLFunctions_4_5_Core>
|
||||||
|
#include <QOPenGLShaderProgram>
|
||||||
|
#include "../Painting/Painting.h"
|
||||||
|
#include <QOffscreenSurface>
|
||||||
|
|
||||||
|
namespace Renderer
|
||||||
|
{
|
||||||
|
class PaintingRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static PaintingRenderer& instance();
|
||||||
|
bool exportPainting(const QString& path, Painting& painting, const QSize& size, float supersampling = 2.f);
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<QOpenGLShaderProgram> shader;
|
||||||
|
std::jthread thread;
|
||||||
|
QOffscreenSurface surface;
|
||||||
|
QOpenGLContext context;
|
||||||
|
std::atomic<bool> initialized = false;
|
||||||
|
bool drawFinished = true;
|
||||||
|
bool needDraw = false;
|
||||||
|
std::condition_variable draw;
|
||||||
|
std::mutex drawMutex;
|
||||||
|
Painting* painting;
|
||||||
|
QString path;
|
||||||
|
QSize size;
|
||||||
|
float supersampling;
|
||||||
|
std::pair<QImage, QPointF> result;
|
||||||
|
|
||||||
|
PaintingRenderer();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag
|
||||||
program.bind();
|
program.bind();
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
|
gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, i, painting.buffers[i]);
|
||||||
glMain->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[6]);
|
gl->BindBufferBase(GL_UNIFORM_BUFFER, 1, painting.buffers[6]);
|
||||||
gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y);
|
gl->Uniform2i(gl->GetUniformLocation(program.programId(), "pixelOffset"), static_cast<GLsizei>(pageSize) * page.x, static_cast<GLsizei>(pageSize) * page.y);
|
||||||
gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
gl->BindImageTexture(0, painting.baseColor, level, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
|
||||||
gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
|
gl->BindImageTexture(1, painting.metallicRoughness, level, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include "EPaperTest.h"
|
||||||
|
#include "CppUnitTest.h"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <qlabel.h>
|
||||||
|
|
||||||
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
|
|
||||||
|
namespace UnitTest
|
||||||
|
{
|
||||||
|
TEST_CLASS(EPaperTest)
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
char* argv[1];
|
||||||
|
int argc;
|
||||||
|
public:
|
||||||
|
EPaperTest() :argv{ (char*)"" }, argc(1) {}
|
||||||
|
|
||||||
|
TEST_METHOD(TestBothSidesRound)
|
||||||
|
{
|
||||||
|
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
QLabel w;
|
||||||
|
w.setFixedSize({296,128});
|
||||||
|
QImage image(QSize(296, 128), QImage::Format_RGB32);
|
||||||
|
image.fill(Qt::red);
|
||||||
|
w.setPixmap(QPixmap::fromImage(image));
|
||||||
|
w.show();
|
||||||
|
a.exec();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
#pragma once
|
|
@ -3,6 +3,8 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include "Renderer/Painting/Painting.h"
|
#include "Renderer/Painting/Painting.h"
|
||||||
#include "Renderer/Painting/MaterialStyleStroke.h"
|
#include "Renderer/Painting/MaterialStyleStroke.h"
|
||||||
|
#include "Renderer/Preview/PaintingRenderer.h"
|
||||||
|
#include <util/PaintingUtil.h>
|
||||||
|
|
||||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
using namespace Renderer;
|
using namespace Renderer;
|
||||||
|
@ -17,35 +19,11 @@ namespace UnitTest
|
||||||
public:
|
public:
|
||||||
PaintingTest() :argv{ (char*)"" }, argc(1) {}
|
PaintingTest() :argv{ (char*)"" }, argc(1) {}
|
||||||
|
|
||||||
TEST_METHOD_INITIALIZE(initialize)
|
|
||||||
{
|
|
||||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
||||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
||||||
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
||||||
}
|
|
||||||
TEST_METHOD(TestBothSidesRound)
|
TEST_METHOD(TestBothSidesRound)
|
||||||
{
|
{
|
||||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QApplication app(argc, argv);
|
||||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
auto painting = PaintingUtil::transfromToPainting("E:\\3D Objects\\dougong\\paintings\\Test1\\Test1.json");
|
||||||
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
PaintingRenderer::instance().exportPainting("E:\\3D Objects\\dougong\\paintings\\Test1\\Test1.png", painting, QSize(5910, 10940));
|
||||||
QApplication a(argc, argv);
|
|
||||||
class StyleStrokeRadialGradient : public Renderer::ElementStyle
|
|
||||||
{
|
|
||||||
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
|
|
||||||
{
|
|
||||||
std::map<float, Material> materialMap = {
|
|
||||||
{0.20, Material{QColor(255,255,255)}},
|
|
||||||
{0.60, Material{QColor(165,176,207)}},
|
|
||||||
{1.00, Material{QColor(58,64,151)}}
|
|
||||||
};
|
|
||||||
return { BaseStyle(std::make_shared<TransformStyle>(),
|
|
||||||
std::make_shared<MaterialStyleStroke>(60, StrokeType::kBothSides, StrokeEndType::kRound,
|
|
||||||
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
|
|
||||||
}
|
|
||||||
} style;
|
|
||||||
TestPaintingGLWidget w(style);
|
|
||||||
w.show();
|
|
||||||
a.exec();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,7 @@
|
||||||
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|x64'">input</DynamicSource>
|
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|x64'">input</DynamicSource>
|
||||||
<QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).moc</QtMocFileName>
|
<QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).moc</QtMocFileName>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="EPaperTest.cpp" />
|
||||||
<ClCompile Include="LayerStyleTest.cpp" />
|
<ClCompile Include="LayerStyleTest.cpp" />
|
||||||
<ClCompile Include="PaintingTest.cpp">
|
<ClCompile Include="PaintingTest.cpp">
|
||||||
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">input</DynamicSource>
|
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">input</DynamicSource>
|
||||||
|
@ -136,6 +137,9 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtMoc Include="PaintingTest.h" />
|
<QtMoc Include="PaintingTest.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="EPaperTest.h" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
|
||||||
<Import Project="$(QtMsBuild)\qt.targets" />
|
<Import Project="$(QtMsBuild)\qt.targets" />
|
||||||
|
|
|
@ -54,5 +54,13 @@
|
||||||
<ClCompile Include="LayerStyleTest.cpp">
|
<ClCompile Include="LayerStyleTest.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="EPaperTest.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="EPaperTest.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue