diff --git a/Source/EmberCommon/EmberCommon.h b/Source/EmberCommon/EmberCommon.h index 5673dc7..d986099 100644 --- a/Source/EmberCommon/EmberCommon.h +++ b/Source/EmberCommon/EmberCommon.h @@ -647,7 +647,9 @@ static bool StripsRender(RendererBase* renderer, Ember& ember, vector& f ember.m_Quality /= strips; ember.m_FinalRasH = realHeight; ember.m_CenterY = centerY; - renderer->SetEmber(ember);//Further processing will require the dimensions to match the original ember, so re-assign. + + if (strips > 1) + renderer->SetEmber(ember);//Further processing will require the dimensions to match the original ember, so re-assign. if (success) allStripsFinished(ember); diff --git a/Source/Fractorium/FinalRenderDialog.cpp b/Source/Fractorium/FinalRenderDialog.cpp index 12bc489..b5d2487 100644 --- a/Source/Fractorium/FinalRenderDialog.cpp +++ b/Source/Fractorium/FinalRenderDialog.cpp @@ -163,6 +163,27 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF m_SupersampleSpin->setValue(m_Settings->FinalSupersample()); m_StripsSpin->setValue(int(m_Settings->FinalStrips())); Scale(eScaleType(m_Settings->FinalScale())); + auto menu = new QMenu(this); + auto add10 = new QAction("Add 10% quality", this); add10->setProperty("tag", QVariant(0.10)); + auto add25 = new QAction("Add 25% quality", this); add25->setProperty("tag", QVariant(0.25)); + auto add50 = new QAction("Add 50% quality", this); add50->setProperty("tag", QVariant(0.50)); + auto add100 = new QAction("Add 100% quality", this); add100->setProperty("tag", QVariant(1.0)); + auto add200 = new QAction("Add 200% quality", this); add200->setProperty("tag", QVariant(2.0)); + menu->addAction(add10); + menu->addAction(add25); + menu->addAction(add50); + menu->addAction(add100); + menu->addAction(add200); + ui.FinalRenderBumpQualityStartButton->setMenu(menu); + ui.FinalRenderBumpQualityStartButton->setProperty("tag", add25->property("tag")); + ui.FinalRenderBumpQualityStartButton->setText(add25->text()); + ui.FinalRenderBumpQualityStartButton->setEnabled(false); + connect(ui.FinalRenderBumpQualityStartButton, SIGNAL(clicked()), this, SLOT(OnQualityBumpClicked())); + connect(add10, SIGNAL(triggered()), this, SLOT(OnQualityBumpClicked())); + connect(add25, SIGNAL(triggered()), this, SLOT(OnQualityBumpClicked())); + connect(add50, SIGNAL(triggered()), this, SLOT(OnQualityBumpClicked())); + connect(add100, SIGNAL(triggered()), this, SLOT(OnQualityBumpClicked())); + connect(add200, SIGNAL(triggered()), this, SLOT(OnQualityBumpClicked())); int index = 0; #ifdef _WIN32 @@ -225,6 +246,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF w = SetTabOrder(this, w, m_PrefixEdit); w = SetTabOrder(this, w, m_SuffixEdit); w = SetTabOrder(this, w, ui.FinalRenderTextOutput); + w = SetTabOrder(this, w, ui.FinalRenderBumpQualityStartButton); w = SetTabOrder(this, w, ui.FinalRenderStartButton); w = SetTabOrder(this, w, ui.FinalRenderPauseButton); w = SetTabOrder(this, w, ui.FinalRenderStopButton); @@ -435,6 +457,7 @@ void FractoriumFinalRenderDialog::OnDoAllCheckBoxStateChanged(int state) ui.FinalRenderDoSequenceCheckBox->setChecked(false); ui.FinalRenderDoSequenceCheckBox->setEnabled(ui.FinalRenderDoAllCheckBox->isChecked()); + ui.FinalRenderBumpQualityStartButton->setEnabled(false); } /// @@ -475,6 +498,8 @@ void FractoriumFinalRenderDialog::OnApplyAllCheckBoxStateChanged(int state) { if (state && m_Controller.get()) m_Controller->SyncGuiToEmbers(); + + ui.FinalRenderBumpQualityStartButton->setEnabled(false); } /// @@ -725,6 +750,32 @@ void FractoriumFinalRenderDialog::OnSuffixChanged(const QString& s) Path(m_Controller->ComposePath(m_Controller->Name())); } +/// +/// Increase the quality of the last render and start rendering again. +/// Note this is only when rendering a single image with no strips. +/// +void FractoriumFinalRenderDialog::OnQualityBumpClicked() +{ + auto act = qobject_cast(sender()); + auto tbtn = qobject_cast(sender()); + + if (tbtn) + { + if (m_Controller.get()) + { + double d = tbtn->property("tag").toDouble(); + m_QualitySpin->SetValueStealth(std::ceil(Quality() + (Quality() * d))); + m_Controller->BumpQualityRender(d); + tbtn->setEnabled(false); + } + } + else if (act) + { + ui.FinalRenderBumpQualityStartButton->setText(act->text()); + ui.FinalRenderBumpQualityStartButton->setProperty("tag", act->property("tag")); + } +} + /// /// Start the render process. /// @@ -947,6 +998,7 @@ bool FractoriumFinalRenderDialog::SetMemory() else ui.FinalRenderTextOutput->clear(); + ui.FinalRenderBumpQualityStartButton->setEnabled(false); return true; } diff --git a/Source/Fractorium/FinalRenderDialog.h b/Source/Fractorium/FinalRenderDialog.h index 5c09661..79a73b4 100644 --- a/Source/Fractorium/FinalRenderDialog.h +++ b/Source/Fractorium/FinalRenderDialog.h @@ -111,6 +111,7 @@ public slots: void OnExtIndexChanged(int d); void OnPrefixChanged(const QString& s); void OnSuffixChanged(const QString& s); + void OnQualityBumpClicked(); void OnRenderClicked(bool checked); void OnPauseClicked(bool checked); void OnCancelRenderClicked(bool checked); diff --git a/Source/Fractorium/FinalRenderDialog.ui b/Source/Fractorium/FinalRenderDialog.ui index 333bf7a..727e4dd 100644 --- a/Source/Fractorium/FinalRenderDialog.ui +++ b/Source/Fractorium/FinalRenderDialog.ui @@ -1192,6 +1192,25 @@ + + + + Add Quality + + + QToolButton::MenuButtonPopup + + + Qt::ToolButtonTextOnly + + + false + + + Qt::NoArrow + + + diff --git a/Source/Fractorium/FinalRenderEmberController.cpp b/Source/Fractorium/FinalRenderEmberController.cpp index 7f3e595..f617221 100644 --- a/Source/Fractorium/FinalRenderEmberController.cpp +++ b/Source/Fractorium/FinalRenderEmberController.cpp @@ -292,9 +292,10 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD } else if (m_Renderer.get())//Render a single image. { + bool isBump = m_IsQualityBump && m_GuiState.m_Strips == 1;//Should never get called with m_IsQualityBump otherwise, but check one last time to be safe. m_ImageCount = 1; m_Ember->m_TemporalSamples = 1; - m_Renderer->SetEmber(*m_Ember); + m_Renderer->SetEmber(*m_Ember, isBump ? eProcessAction::KEEP_ITERATING : eProcessAction::FULL_RENDER); m_Renderer->PrepFinalAccumVector(m_FinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run(). m_Stats.Clear(); Memset(m_FinalImage); @@ -416,6 +417,35 @@ bool FinalRenderEmberController::Render() return false; } + +/// +/// Increase the quality of the last render and start rendering again. +/// Note this is only when rendering a single image with no strips. +/// +/// The amount to increase the quality by, expressed as a decimal percentage. Eg: 0.5 means to increase by 50%. +/// True if nothing went wrong, else false. +template +bool FinalRenderEmberController::BumpQualityRender(double d) +{ + m_Ember->m_Quality += std::ceil(m_Ember->m_Quality * d); + m_Renderer->SetEmber(*m_Ember, eProcessAction::KEEP_ITERATING, true); + QString filename = m_FinalRenderDialog->Path(); + + if (filename == "") + { + m_Fractorium->ShowCritical("File Error", "Please enter a valid path and filename for the output."); + return false; + } + + m_IsQualityBump = true; + auto iterCount = m_Renderer->TotalIterCount(1); + m_FinalRenderDialog->ui.FinalRenderParamsTable->item(m_FinalRenderDialog->m_ItersCellIndex, 1)->setText(ToString(iterCount)); + m_FinalRenderDialog->ui.FinalRenderTextOutput->setText("Preparing all parameters.\n"); + m_Result = QtConcurrent::run(m_FinalRenderFunc); + m_Settings->sync(); + return true; +} + /// /// Stop rendering and initialize a new renderer, using the specified type and the options on the final render dialog. /// @@ -803,6 +833,7 @@ template void FinalRenderEmberController::HandleFinishedProgress() { auto finishedCountCached = m_FinishedImageCount.load();//Make sure to use the same value throughout this function even if the atomic is changing. + bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1; if (m_FinishedImageCount.load() != m_ImageCount) ResetProgress(false); @@ -811,6 +842,7 @@ void FinalRenderEmberController::HandleFinishedProgress() QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, int((float(finishedCountCached) / float(m_ImageCount)) * 100))); QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(const QString&, ToString(finishedCountCached) + " / " + ToString(m_ImageCount))); + QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderBumpQualityStartButton, "setEnabled", Qt::QueuedConnection, Q_ARG(bool, !doAll && m_Renderer.get() && m_GuiState.m_Strips == 1)); } /// diff --git a/Source/Fractorium/FinalRenderEmberController.h b/Source/Fractorium/FinalRenderEmberController.h index 7263762..7fde3ae 100644 --- a/Source/Fractorium/FinalRenderEmberController.h +++ b/Source/Fractorium/FinalRenderEmberController.h @@ -69,6 +69,7 @@ public: virtual tuple SyncAndComputeMemory() { return tuple(0, 0, 0); } virtual double OriginalAspect() { return 1; } virtual QString ComposePath(const QString& name) { return ""; } + virtual bool BumpQualityRender(double d) { return false; } virtual void CancelRender() { } virtual QString CheckMemory(const tuple& p) { return ""; } @@ -78,6 +79,7 @@ public: protected: bool m_Run = false; + bool m_IsQualityBump = false; size_t m_ImageCount = 0; std::atomic m_FinishedImageCount; @@ -114,6 +116,7 @@ public: #endif virtual void SetEmber(size_t index, bool verbatim) override; virtual bool Render() override; + virtual bool BumpQualityRender(double d) override; virtual bool CreateRenderer(eRendererType renderType, const vector>& devices, bool updatePreviews, bool shared = true) override; virtual int ProgressFunc(Ember& ember, void* foo, double fraction, int stage, double etaMs) override; virtual size_t Index() const override { return m_Ember->m_Index; } diff --git a/Source/Fractorium/FractoriumPalette.cpp b/Source/Fractorium/FractoriumPalette.cpp index cd332ac..9c0d4d0 100644 --- a/Source/Fractorium/FractoriumPalette.cpp +++ b/Source/Fractorium/FractoriumPalette.cpp @@ -613,14 +613,13 @@ void Fractorium::SetPaletteFileComboIndex(const string& filename) template void FractoriumEmberController::ClearColorCurves(int i) { - Update([&] + UpdateAll([&](Ember& ember, bool isMain) { if (i < 0) - m_Ember.m_Curves.Init(); + ember.m_Curves.Init(); else - m_Ember.m_Curves.Init(i); - - }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY); + ember.m_Curves.Init(i); + }, true, m_Renderer->EarlyClip() ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY, m_Fractorium->ApplyAll()); FillCurvesControl(); } diff --git a/Source/Fractorium/FractoriumXaos.cpp b/Source/Fractorium/FractoriumXaos.cpp index 0d819e2..c6d0353 100644 --- a/Source/Fractorium/FractoriumXaos.cpp +++ b/Source/Fractorium/FractoriumXaos.cpp @@ -206,7 +206,10 @@ void Fractorium::FillXaosTable() template void FractoriumEmberController::ClearXaos() { - Update([&] { m_Ember.ClearXaos(); }); + UpdateAll([&](Ember& ember, bool isMain) + { + ember.ClearXaos(); + }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); FillXaos(); FillAppliedXaos(); }