From dad2c1fa59d93efcab8b80a82ff8264b3f257ba9 Mon Sep 17 00:00:00 2001 From: wuyize Date: Tue, 25 Apr 2023 14:49:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=BC=E5=87=BAPNG?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArchitectureColoredPainting.vcxproj | 2 + ...rchitectureColoredPainting.vcxproj.filters | 6 + .../src/Editor/EditorWidget.cpp | 9 + .../src/Editor/EditorWidgetItem.cpp | 288 +++++++++++------- .../src/Editor/EditorWidgetItem.h | 5 +- .../src/Renderer/Preview/PaintingRenderer.cpp | 82 +++++ .../src/Renderer/Preview/PaintingRenderer.h | 35 +++ .../src/Renderer/VirtualTextureManager.cpp | 2 +- UnitTest/EPaperTest.cpp | 36 +++ UnitTest/EPaperTest.h | 1 + UnitTest/PaintingTest.cpp | 32 +- UnitTest/UnitTest.vcxproj | 4 + UnitTest/UnitTest.vcxproj.filters | 8 + 13 files changed, 372 insertions(+), 138 deletions(-) create mode 100644 ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.cpp create mode 100644 ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.h create mode 100644 UnitTest/EPaperTest.cpp create mode 100644 UnitTest/EPaperTest.h diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj index d1a31e2..3480a6f 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj @@ -162,6 +162,7 @@ + @@ -253,6 +254,7 @@ + diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters index 70a7d95..1da6526 100644 --- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters +++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters @@ -282,6 +282,9 @@ Source Files + + Source Files\Renderer\Preview + @@ -570,6 +573,9 @@ Header Files + + Header Files\Renderer\Preview + diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp index f20efa6..629ae62 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidget.cpp @@ -69,10 +69,12 @@ void EditorWidget::initFileMenu() auto* actionOpen = new QAction(QStringLiteral("打开"), fileMenuButton); auto* actionSave = new QAction(QStringLiteral("保存"), fileMenuButton); auto* actionSaveAs = new QAction(QStringLiteral("另存为"), fileMenuButton); + auto* actionExport = new QAction(QStringLiteral("导出"), fileMenuButton); fileMenuButton->addMenuAction(actionCreate); fileMenuButton->addMenuAction(actionOpen); fileMenuButton->addMenuAction(actionSave); fileMenuButton->addMenuAction(actionSaveAs); + fileMenuButton->addMenuAction(actionExport); connect(actionCreate, &QAction::triggered, [this] { static int count = 0; const int prevCount = this->tabWidget->count(); @@ -108,6 +110,13 @@ void EditorWidget::initFileMenu() item->saveAs(fileName); } }); + connect(actionExport, &QAction::triggered, this, [this] { + auto* item = dynamic_cast(this->tabWidget->currentWidget()); + if (item != nullptr) + { + item->exportAs(); + } + }); } void EditorWidget::initProjectMenu() diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp index d6f4f60..2d5af08 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.cpp @@ -1,126 +1,131 @@ #include "EditorWidgetItem.h" #include "EditorWidget.h" #include "DataManager/ProjectDataManager.h" +#include "../Renderer/Preview/PaintingRenderer.h" +#include "util/PaintingUtil.h" #include #include #include #include +#include +#include +#include -EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(parent) +EditorWidgetItem::EditorWidgetItem(QString filePath, QWidget* parent) : QWidget(parent) { - QImage x; - this->parent = parent; - displayLayer = nullptr; - displayElement = nullptr; - ui.setupUi(this); - previewWindow = ui.Preview; - treeWidget = ui.LayerTree; - this->filePath = filePath; - elementInfoDisplayWidget = ui.ElementDisplay; - layerInfoDisplayWidget = ui.LayerDisplay; - elementInfoDisplayWidget->enableEdit(); - qDebug() << layerInfoDisplayWidget; - qDebug() << elementInfoDisplayWidget; - auto centralRefresh = [this]() { - layerInfoDisplayWidget->refresh(); - treeWidget->refresh(); + QImage x; + this->parent = parent; + displayLayer = nullptr; + displayElement = nullptr; + ui.setupUi(this); + previewWindow = ui.Preview; + treeWidget = ui.LayerTree; + this->filePath = filePath; + elementInfoDisplayWidget = ui.ElementDisplay; + layerInfoDisplayWidget = ui.LayerDisplay; + elementInfoDisplayWidget->enableEdit(); + qDebug() << layerInfoDisplayWidget; + qDebug() << elementInfoDisplayWidget; + auto centralRefresh = [this]() { + layerInfoDisplayWidget->refresh(); + treeWidget->refresh(); previewWindow->refresh(); elementInfoDisplayWidget->lazyRefresh(); - }; - connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh); + }; + connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh); connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh); connect(elementInfoDisplayWidget, &ElementPoolWidget::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::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh); // connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh); - connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange); - // connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this, - // &EditorWidgetItem::triggerRefreshPreview); - // connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this, - // &EditorWidgetItem::triggerRefreshPreview); - //connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); - // connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh); - // &EditorWidget::triggerRefreshPreview); - // test - QFile settingFile; - //settingFile.setFileName("../data.json"); + connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange); + // connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this, + // &EditorWidgetItem::triggerRefreshPreview); + // connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this, + // &EditorWidgetItem::triggerRefreshPreview); + //connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); + // connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh); + // &EditorWidget::triggerRefreshPreview); + // test + QFile settingFile; + //settingFile.setFileName("../data.json"); settingFile.setFileName(filePath); - settingFile.open(QFile::ReadOnly); - QByteArray setting = settingFile.readAll().trimmed(); - QJsonParseError jError; - QJsonDocument jsonDoc(QJsonDocument::fromJson(setting, &jError)); - qDebug() << jsonDoc.object().value("height").toDouble(); - qDebug() << jError.errorString(); - ProjectData data; - data.fileHome = QFileInfo(filePath).absolutePath(); - data.width = jsonDoc.object().value("height").toInt(); - data.height = jsonDoc.object().value("width").toInt(); - data.zoomX = 1.0; - data.zoomY = 1.0; - data.item = this; - ProjectDataManager::Instance()->addProjectData(data); - // end test - QJsonObject source = jsonDoc.object(); + settingFile.open(QFile::ReadOnly); + QByteArray setting = settingFile.readAll().trimmed(); + QJsonParseError jError; + QJsonDocument jsonDoc(QJsonDocument::fromJson(setting, &jError)); + qDebug() << jsonDoc.object().value("height").toDouble(); + qDebug() << jError.errorString(); + ProjectData data; + data.fileHome = QFileInfo(filePath).absolutePath(); + data.width = jsonDoc.object().value("height").toInt(); + data.height = jsonDoc.object().value("width").toInt(); + data.zoomX = 1.0; + data.zoomY = 1.0; + data.item = this; + ProjectDataManager::Instance()->addProjectData(data); + // end test + QJsonObject source = jsonDoc.object(); elementManager = new ElementManager(source, QFileInfo(filePath).absolutePath()); - layerManager = new LayerManager(source, elementManager); - elementInfoDisplayWidget->setElementManager(elementManager); - treeWidget->elementManager = elementManager; - //qDebug() << layerManager->toJson(); - previewWindow->initialize(layerManager,QSize(jsonDoc.object().value("width").toInt(),jsonDoc.object().value("height").toInt())); - if (source.contains("metallic")) - previewWindow->canvasMetallic = jsonDoc.object().value("metallic").toDouble(); - else - previewWindow->canvasMetallic = 0; - if (source.contains("roughness")) - previewWindow->canvasRoughness = jsonDoc.object().value("roughness").toDouble(); - else - previewWindow->canvasRoughness = 0.5; - - - if (layerManager->getRoot() != nullptr) - { - treeWidget->root = layerManager->getRoot(); + layerManager = new LayerManager(source, elementManager); + elementInfoDisplayWidget->setElementManager(elementManager); + treeWidget->elementManager = elementManager; + //qDebug() << layerManager->toJson(); + previewWindow->initialize(layerManager, QSize(jsonDoc.object().value("width").toInt(), jsonDoc.object().value("height").toInt())); + if (source.contains("metallic")) + previewWindow->canvasMetallic = jsonDoc.object().value("metallic").toDouble(); + else + previewWindow->canvasMetallic = 0; + if (source.contains("roughness")) + previewWindow->canvasRoughness = jsonDoc.object().value("roughness").toDouble(); + else + previewWindow->canvasRoughness = 0.5; + + + if (layerManager->getRoot() != nullptr) + { + treeWidget->root = layerManager->getRoot(); treeWidget->refresh(); treeWidget->addTopLevelItem(treeWidget->root->getQTreeItem()); - } - this->backgroundColor = source.value("background-color").toVariant().value(); + } + this->backgroundColor = source.value("background-color").toVariant().value(); this->projectName = source.value("project-name").toString(); - qDebug() << this->backgroundColor; - qDebug() << this->projectName; + qDebug() << this->backgroundColor; + qDebug() << this->projectName; elementInfoDisplayWidget->refresh(); - QTimer::singleShot(300, this, [this, centralRefresh]() { - handleBackgroundColorChange(this->backgroundColor); - handleProjectNameChange(this->projectName); - centralRefresh(); - }); + QTimer::singleShot(300, this, [this, centralRefresh]() { + handleBackgroundColorChange(this->backgroundColor); + handleProjectNameChange(this->projectName); + centralRefresh(); + }); } EditorWidgetItem::~EditorWidgetItem() { } -void EditorWidgetItem::paintEvent(QPaintEvent *event) +void EditorWidgetItem::paintEvent(QPaintEvent* event) { - QPainter painter(this); + QPainter painter(this); - // 设置画刷的颜色为灰色,并填充整个窗口区域 - painter.setBrush(Qt::gray); - painter.drawRect(this->rect()); + // 设置画刷的颜色为灰色,并填充整个窗口区域 + painter.setBrush(Qt::gray); + painter.drawRect(this->rect()); } -void EditorWidgetItem::onLayerChange(LayerWrapper *layer) +void EditorWidgetItem::onLayerChange(LayerWrapper* layer) { - displayLayer = layer; - // TODO : notify InfoDisplayWidget and update - ui.LayerDisplay->setLayer(layer); - this->update(); + displayLayer = layer; + // TODO : notify InfoDisplayWidget and update + ui.LayerDisplay->setLayer(layer); + this->update(); } void EditorWidgetItem::triggerRefreshPreview() { - previewWindow->update(); + previewWindow->update(); } void EditorWidgetItem::save() const @@ -132,36 +137,103 @@ void EditorWidgetItem::saveAs(QString filePath) const { saveImpl(filePath); 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"); - } - for (auto& ele : elementManager->elements) - { - auto e = dynamic_cast(ele); - if (e != nullptr) - { - QString fileName = e->jsonSource["data"].toObject()["include"].toString(); - QString src = srcHome + fileName; + } + for (auto& ele : elementManager->elements) + { + auto e = dynamic_cast(ele); + if (e != nullptr) + { + QString fileName = e->jsonSource["data"].toObject()["include"].toString(); + QString src = srcHome + fileName; QString dst = QFileInfo(filePath).absolutePath() + fileName; 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::max(), &widthTextField)); + heightTextField.setValidator(new FixedIntValidator(1, std::numeric_limits::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 { QJsonObject source1 = layerManager->toJson(); QJsonObject source2 = elementManager->toJson(); - QJsonObject json; + QJsonObject json; json.insert("roughness", previewWindow->canvasRoughness); json.insert("metallic", previewWindow->canvasMetallic); json.insert("width", previewWindow->referSize.width()); json.insert("height", previewWindow->referSize.height()); json.insert("root-layer", source1.value("root-layer")); - json.insert("elements", source2.value("elements")); - json.insert("project-name", this->projectName); + json.insert("elements", source2.value("elements")); + json.insert("project-name", this->projectName); json.insert("background-color", QJsonValue::fromVariant(QVariant::fromValue(this->backgroundColor))); QJsonDocument doc(json); QFile file(filePath); @@ -179,17 +251,17 @@ void EditorWidgetItem::handleBackgroundColorChange(const QColor& color) void EditorWidgetItem::handleProjectNameChange(const QString& name) { this->projectName = name; - auto parent = dynamic_cast(this->parent); - qDebug() << name << " " << parent<<" "<(this->parent); + qDebug() << name << " " << parent << " " << this; + if (parent != nullptr) + { parent->renameTab(this, name); - } + } } void EditorWidgetItem::handleCanvasSizeChange(const QSize& size) { - previewWindow->resize(size); + previewWindow->resize(size); } void EditorWidgetItem::handleCanvasRoughnessChange(const float& roughness) @@ -204,7 +276,7 @@ void EditorWidgetItem::handleCanvasMetallicChange(const float& metallic) QSize EditorWidgetItem::getCanvasReferSize() const { - return previewWindow->referSize; + return previewWindow->referSize; } float EditorWidgetItem::getCanvasRoughness() const diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h index 92097dc..b95c0df 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetItem.h @@ -32,7 +32,7 @@ class EditorWidgetItem : public QWidget GraphicElement *displayElement; QWidget* parent; void saveImpl(QString filePath)const; -public: + public: // PROJECT INFO QString filePath; QString projectName; @@ -43,7 +43,8 @@ public: ~EditorWidgetItem(); void paintEvent(QPaintEvent *event) override; void save() const; - void saveAs(QString filePath)const; + void saveAs(QString filePath) const; + void exportAs(); void handleBackgroundColorChange(const QColor& color); void handleProjectNameChange(const QString& name); void handleCanvasSizeChange(const QSize& size); diff --git a/ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.cpp b/ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.cpp new file mode 100644 index 0000000..3b90fea --- /dev/null +++ b/ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.cpp @@ -0,0 +1,82 @@ +#include "PaintingRenderer.h" +#include + +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 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(); + shader = std::make_unique(); + 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 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(); +} diff --git a/ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.h b/ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.h new file mode 100644 index 0000000..3c92cfc --- /dev/null +++ b/ArchitectureColoredPainting/src/Renderer/Preview/PaintingRenderer.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include +#include "../Painting/Painting.h" +#include + +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 shader; + std::jthread thread; + QOffscreenSurface surface; + QOpenGLContext context; + std::atomic 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 result; + + PaintingRenderer(); + }; + +} + diff --git a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp index c59249f..ff2b6ba 100644 --- a/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp +++ b/ArchitectureColoredPainting/src/Renderer/VirtualTextureManager.cpp @@ -211,7 +211,7 @@ void Renderer::VirtualTextureManager::pageCommitmentById(const glm::u16vec2& pag program.bind(); for (int i = 0; i < 6; 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(pageSize) * page.x, static_cast(pageSize) * page.y); 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); diff --git a/UnitTest/EPaperTest.cpp b/UnitTest/EPaperTest.cpp new file mode 100644 index 0000000..4030a52 --- /dev/null +++ b/UnitTest/EPaperTest.cpp @@ -0,0 +1,36 @@ +#include "EPaperTest.h" +#include "CppUnitTest.h" +#include +#include +#include + +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(); + } + }; + + +} diff --git a/UnitTest/EPaperTest.h b/UnitTest/EPaperTest.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/UnitTest/EPaperTest.h @@ -0,0 +1 @@ +#pragma once diff --git a/UnitTest/PaintingTest.cpp b/UnitTest/PaintingTest.cpp index 29ae33a..3a23819 100644 --- a/UnitTest/PaintingTest.cpp +++ b/UnitTest/PaintingTest.cpp @@ -3,6 +3,8 @@ #include #include "Renderer/Painting/Painting.h" #include "Renderer/Painting/MaterialStyleStroke.h" +#include "Renderer/Preview/PaintingRenderer.h" +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Renderer; @@ -17,35 +19,11 @@ namespace UnitTest public: 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) { - QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - QApplication a(argc, argv); - class StyleStrokeRadialGradient : public Renderer::ElementStyle - { - virtual std::vector toBaseStyles() const override - { - std::map 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(), - std::make_shared(60, StrokeType::kBothSides, StrokeEndType::kRound, - std::make_shared(materialMap, false))) }; - } - } style; - TestPaintingGLWidget w(style); - w.show(); - a.exec(); + QApplication app(argc, argv); + auto painting = PaintingUtil::transfromToPainting("E:\\3D Objects\\dougong\\paintings\\Test1\\Test1.json"); + PaintingRenderer::instance().exportPainting("E:\\3D Objects\\dougong\\paintings\\Test1\\Test1.png", painting, QSize(5910, 10940)); } }; diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index ee2464b..078bcf5 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -111,6 +111,7 @@ input %(Filename).moc + input @@ -136,6 +137,9 @@ + + + diff --git a/UnitTest/UnitTest.vcxproj.filters b/UnitTest/UnitTest.vcxproj.filters index df5ed3f..5e548ff 100644 --- a/UnitTest/UnitTest.vcxproj.filters +++ b/UnitTest/UnitTest.vcxproj.filters @@ -54,5 +54,13 @@ Source Files + + Source Files + + + + + Header Files + \ No newline at end of file