diff --git a/Source/Ember/Ember.cpp b/Source/Ember/Ember.cpp index a2b33a5..13a4a29 100644 --- a/Source/Ember/Ember.cpp +++ b/Source/Ember/Ember.cpp @@ -62,8 +62,6 @@ uint Timing::m_ProcessorCount; template<> vector, vector>> XmlToEmber::m_BadVariationNames = vector, vector>>(); \ template EMBER_API class Point; \ template EMBER_API struct Color; \ - template EMBER_API class Palette; \ - template EMBER_API class PaletteList; \ template EMBER_API class Iterator; \ template EMBER_API class StandardIterator; \ template EMBER_API class XaosIterator; \ @@ -457,6 +455,10 @@ uint Timing::m_ProcessorCount; EXPORT_SINGLE_TYPE_EMBER(float) EXPORT_TWO_TYPE_EMBER(float, float) +//Only ever use float palettes. +template EMBER_API class Palette; +template EMBER_API class PaletteList; + #ifdef DO_DOUBLE EXPORT_SINGLE_TYPE_EMBER(double) EXPORT_TWO_TYPE_EMBER(double, float) diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index 330928c..a6ce63c 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -1287,6 +1287,11 @@ EmberStats Renderer::Iterate(size_t iterCount, size_t temporalSample m_Samples[threadIndex][0].m_Y = m_Rand[threadIndex].template Frand11(); m_Samples[threadIndex][0].m_Z = 0;//m_Ember.m_CamZPos;//Apo set this to 0, then made the user use special variations to kick it. It seems easier to just set it to zpos. m_Samples[threadIndex][0].m_ColorX = m_Rand[threadIndex].template Frand01(); + + //Check if the user wanted to suspend the process. + while (Paused()) + std::this_thread::sleep_for(500ms); + //Finally, iterate. //t.Tic(); //Iterating, loop 3. diff --git a/Source/Ember/RendererBase.cpp b/Source/Ember/RendererBase.cpp index a55d476..40d8d12 100644 --- a/Source/Ember/RendererBase.cpp +++ b/Source/Ember/RendererBase.cpp @@ -541,9 +541,12 @@ void RendererBase::LeaveFinalAccum() { m_FinalAccumCs.unlock(); m_InFinalAccum = void RendererBase::EnterResize() { m_ResizeCs.lock(); } void RendererBase::LeaveResize() { m_ResizeCs.unlock(); } -void RendererBase::Abort() { m_Abort = true; } +void RendererBase::Abort() { m_Abort = true; Pause(false); } bool RendererBase::Aborted() { return m_Abort; } +void RendererBase::Pause(bool pause) { m_Pause = pause; } +bool RendererBase::Paused() { return m_Pause; } + bool RendererBase::InRender() { return m_InRender; } bool RendererBase::InFinalAccum() { return m_InFinalAccum; } diff --git a/Source/Ember/RendererBase.h b/Source/Ember/RendererBase.h index 92fe2a8..fbb2604 100644 --- a/Source/Ember/RendererBase.h +++ b/Source/Ember/RendererBase.h @@ -188,6 +188,8 @@ public: void LeaveResize(); void Abort(); bool Aborted(); + void Pause(bool pause); + bool Paused(); bool InRender(); bool InFinalAccum(); @@ -203,6 +205,7 @@ protected: bool m_ReclaimOnResize = false; bool m_CurvesSet = false; volatile bool m_Abort = false; + volatile bool m_Pause = false; size_t m_SuperRasW; size_t m_SuperRasH; size_t m_SuperSize = 0; diff --git a/Source/Fractorium/FinalRenderDialog.cpp b/Source/Fractorium/FinalRenderDialog.cpp index a62c4ea..3cd5a65 100644 --- a/Source/Fractorium/FinalRenderDialog.cpp +++ b/Source/Fractorium/FinalRenderDialog.cpp @@ -71,7 +71,8 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF connect(m_PrefixEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnPrefixChanged(const QString&)), Qt::QueuedConnection); connect(m_SuffixEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnSuffixChanged(const QString&)), Qt::QueuedConnection); ui.FinalRenderStartButton->disconnect(SIGNAL(clicked(bool))); - connect(ui.FinalRenderStartButton, SIGNAL(clicked(bool)), this, SLOT(OnRenderClicked(bool)), Qt::QueuedConnection); + connect(ui.FinalRenderStartButton, SIGNAL(clicked(bool)), this, SLOT(OnRenderClicked(bool)), Qt::QueuedConnection); + connect(ui.FinalRenderPauseButton, SIGNAL(clicked(bool)), this, SLOT(OnPauseClicked(bool)), Qt::QueuedConnection); connect(ui.FinalRenderStopButton, SIGNAL(clicked(bool)), this, SLOT(OnCancelRenderClicked(bool)), Qt::QueuedConnection); table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); ui.FinalRenderSizeTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); @@ -205,6 +206,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF w = SetTabOrder(this, w, m_SuffixEdit); w = SetTabOrder(this, w, ui.FinalRenderTextOutput); w = SetTabOrder(this, w, ui.FinalRenderStartButton); + w = SetTabOrder(this, w, ui.FinalRenderPauseButton); w = SetTabOrder(this, w, ui.FinalRenderStopButton); w = SetTabOrder(this, w, ui.FinalRenderCloseButton); } @@ -652,7 +654,21 @@ void FractoriumFinalRenderDialog::OnSuffixChanged(const QString& s) void FractoriumFinalRenderDialog::OnRenderClicked(bool checked) { if (CreateControllerFromGUI(true)) + { + Pause(false); m_Controller->Render(); + } +} + +/// +/// Pause or resume the render process. +/// +/// Ignored +void FractoriumFinalRenderDialog::OnPauseClicked(bool checked) +{ + if (m_Controller.get()) + if (m_Controller->Running()) + Pause(!m_Controller->Paused()); } /// @@ -662,7 +678,28 @@ void FractoriumFinalRenderDialog::OnRenderClicked(bool checked) void FractoriumFinalRenderDialog::OnCancelRenderClicked(bool checked) { if (m_Controller.get()) + { + Pause(false); m_Controller->CancelRender(); + } +} + +/// +/// Pause or resume the render process. +/// +/// True to pause, else resume. +void FractoriumFinalRenderDialog::Pause(bool paused) +{ + if (paused) + { + m_Controller->Pause(true); + ui.FinalRenderPauseButton->setText("Resume"); + } + else + { + m_Controller->Pause(false); + ui.FinalRenderPauseButton->setText("Pause"); + } } /// diff --git a/Source/Fractorium/FinalRenderDialog.h b/Source/Fractorium/FinalRenderDialog.h index e0a6677..bd8b205 100644 --- a/Source/Fractorium/FinalRenderDialog.h +++ b/Source/Fractorium/FinalRenderDialog.h @@ -109,7 +109,9 @@ public slots: void OnPrefixChanged(const QString& s); void OnSuffixChanged(const QString& s); void OnRenderClicked(bool checked); + void OnPauseClicked(bool checked); void OnCancelRenderClicked(bool checked); + void Pause(bool paused); virtual void reject() override; protected: diff --git a/Source/Fractorium/FinalRenderDialog.ui b/Source/Fractorium/FinalRenderDialog.ui index 9bdcd7e..6114a78 100644 --- a/Source/Fractorium/FinalRenderDialog.ui +++ b/Source/Fractorium/FinalRenderDialog.ui @@ -1153,6 +1153,22 @@ + + + + true + + + Qt::TabFocus + + + Pause + + + false + + + diff --git a/Source/Fractorium/FinalRenderEmberController.cpp b/Source/Fractorium/FinalRenderEmberController.cpp index 8184607..2ba761c 100644 --- a/Source/Fractorium/FinalRenderEmberController.cpp +++ b/Source/Fractorium/FinalRenderEmberController.cpp @@ -28,7 +28,6 @@ void FinalRenderEmberController::CancelRender() { if (m_Result.isRunning()) { - //tbb::task_group g; std::thread th([&] { m_Run = false; @@ -123,6 +122,7 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD m_XmlWriter.Save(backup.toStdString().c_str(), *m_Ember, 0, true, false, true, false, false); m_FinishedImageCount.store(0); + Pause(false); SyncGuiToRenderer(); FirstOrDefaultRenderer()->m_ProgressParameter = reinterpret_cast(¤tStripForProgress);//When animating, only the first (primary) device has a progress parameter. m_GuiState.m_Strips = VerifyStrips(m_Ember->m_FinalRasH, m_GuiState.m_Strips, @@ -324,6 +324,7 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD QString totalTimeString = "All renders completed in: " + QString::fromStdString(m_TotalTimer.Format(m_TotalTimer.Toc())) + "."; Output(totalTimeString); QFile::remove(backup); + QMetaObject::invokeMethod(m_FinalRenderDialog, "Pause", Qt::QueuedConnection, Q_ARG(bool, false)); m_Run = false; }; } @@ -730,6 +731,46 @@ void FinalRenderEmberController::RenderComplete(Ember& ember) RenderComplete(ember, m_Stats, m_RenderTimer); } +/// +/// Pause or resume the renderer(s). +/// +/// True to pause, false to unpause. +template +void FinalRenderEmberController::Pause(bool pause) +{ + if (m_Renderer.get()) + { + m_Renderer->Pause(pause); + } + else + { + for (auto& r : m_Renderers) + r->Pause(pause); + } +} + +/// +/// Retrieve the paused state of the renderer(s). +/// +/// True if the renderer(s) is paused, else false. +template +bool FinalRenderEmberController::Paused() +{ + if (m_Renderer.get()) + { + return m_Renderer->Paused(); + } + else + { + bool b = !m_Renderers.empty(); + + for (auto& r : m_Renderers) + b &= r->Paused(); + + return b; + } +} + /// /// Handle setting the appropriate progress bar values when an image render has finished. /// This handles single image, animations, and strips. diff --git a/Source/Fractorium/FinalRenderEmberController.h b/Source/Fractorium/FinalRenderEmberController.h index c333151..a5d429b 100644 --- a/Source/Fractorium/FinalRenderEmberController.h +++ b/Source/Fractorium/FinalRenderEmberController.h @@ -71,6 +71,7 @@ public: virtual void CancelRender() { } virtual QString CheckMemory(const tuple& p) { return ""; } + bool Running() { return m_Result.isRunning(); } bool CreateRendererFromGUI(); void Output(const QString& s); @@ -133,6 +134,8 @@ public: EmberNs::Renderer* FirstOrDefaultRenderer(); protected: + virtual void Pause(bool pause) override; + virtual bool Paused() override; void HandleFinishedProgress(); void SaveCurrentRender(Ember& ember); void SaveCurrentRender(Ember& ember, const EmberImageComments& comments, vector& pixels, size_t width, size_t height, bool png16Bit, bool transparency); diff --git a/Source/Fractorium/FractoriumEmberController.cpp b/Source/Fractorium/FractoriumEmberController.cpp index 2520ed5..239066a 100644 --- a/Source/Fractorium/FractoriumEmberController.cpp +++ b/Source/Fractorium/FractoriumEmberController.cpp @@ -32,6 +32,24 @@ FractoriumEmberControllerBase::~FractoriumEmberControllerBase() m_RenderRestartTimer->stop(); } +/// +/// Pause or resume the renderer. +/// +/// True to pause, false to unpause. +void FractoriumEmberControllerBase::Pause(bool pause) +{ + m_Renderer->Pause(pause); +} + +/// +/// Retrieve the paused state of the renderer. +/// +/// True if the renderer is paused, else false. +bool FractoriumEmberControllerBase::Paused() +{ + return m_Renderer->Paused(); +} + /// /// Constructor which passes the main window parameter to the base, initializes the templated members contained in this class. /// Then sets up the parts of the GUI that require templated Widgets, such as the variations tree and the palette table. diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h index d22a487..0e65578 100644 --- a/Source/Fractorium/FractoriumEmberController.h +++ b/Source/Fractorium/FractoriumEmberController.h @@ -245,6 +245,8 @@ public: virtual void ClearUndo() { } virtual void DeleteRenderer() { } virtual GLEmberControllerBase* GLController() { return nullptr; } + virtual void Pause(bool pause); + virtual bool Paused(); bool RenderTimerRunning(); void StartRenderTimer(); void DelayedStartRenderTimer();