diff --git a/Source/Fractorium/CurvesGraphicsView.cpp b/Source/Fractorium/CurvesGraphicsView.cpp
index 091bd03..ef04912 100644
--- a/Source/Fractorium/CurvesGraphicsView.cpp
+++ b/Source/Fractorium/CurvesGraphicsView.cpp
@@ -218,17 +218,17 @@ void CurvesGraphicsView::paintEvent(QPaintEvent* e)
void CurvesGraphicsView::mousePressEvent(QMouseEvent* e)
{
QGraphicsView::mousePressEvent(e);
- auto thresh = devicePixelRatioF() * 4;
- auto findpoint = [&](int x, int y, bool incThresh = false) -> int
+ auto thresh = devicePixelRatioF() * 4;
+ auto findpoint = [&](int x, int y, double thresh) -> int
{
for (int i = 0; i < m_Points[m_Index].size(); i++)
{
auto item = m_Points[m_Index][i];
auto xdist = std::abs(item->pos().x() - x);
auto ydist = std::abs(item->pos().y() - y);
- auto threshAgain = incThresh ? thresh * 2 : thresh;
+ auto threshAgain = thresh;
- if (xdist < threshAgain && ydist < threshAgain)
+ if (xdist < threshAgain && ydist < threshAgain)
return i;
}
@@ -237,12 +237,12 @@ void CurvesGraphicsView::mousePressEvent(QMouseEvent* e)
if (e->button() == Qt::RightButton)
{
- int i = findpoint(e->pos().x(), e->pos().y());
+ int i = findpoint(e->pos().x(), e->pos().y(), thresh);
if (i != -1)
emit PointRemovedSignal(m_Index, i);
}
- else if (findpoint(e->pos().x(), e->pos().y(), true) == -1)
+ else if (findpoint(e->pos().x(), e->pos().y(), thresh * 8) == -1)
{
QRectF rect = scene()->sceneRect();
auto points = m_Points[m_Index];
diff --git a/Source/Fractorium/FinalRenderDialog.cpp b/Source/Fractorium/FinalRenderDialog.cpp
index c79c8de..821742d 100644
--- a/Source/Fractorium/FinalRenderDialog.cpp
+++ b/Source/Fractorium/FinalRenderDialog.cpp
@@ -164,11 +164,11 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF
m_StripsSpin->setValue(int(m_Settings->FinalStrips()));
Scale(eScaleType(m_Settings->FinalScale()));
auto bumpmenu = 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));
+ 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));
bumpmenu->addAction(add10);
bumpmenu->addAction(add25);
bumpmenu->addAction(add50);
@@ -192,7 +192,7 @@ FractoriumFinalRenderDialog::FractoriumFinalRenderDialog(QWidget* p, Qt::WindowF
saamenu->addAction(saaexr);
ui.FinalRenderSaveAgainAsButton->setMenu(saamenu);
ui.FinalRenderSaveAgainAsButton->setProperty("tag", "jpg");
- ui.FinalRenderSaveAgainAsButton->setText("Save again as jpg");
+ ui.FinalRenderSaveAgainAsButton->setText("Save Again as jpg");
ui.FinalRenderSaveAgainAsButton->setEnabled(false);
connect(ui.FinalRenderSaveAgainAsButton, SIGNAL(clicked()), this, SLOT(OnSaveAgainAsClicked()));
connect(ui.FinalRenderBumpQualityStartButton, SIGNAL(clicked()), this, SLOT(OnQualityBumpClicked()));
@@ -823,7 +823,7 @@ void FractoriumFinalRenderDialog::OnSaveAgainAsClicked()
}
else if (act)
{
- ui.FinalRenderSaveAgainAsButton->setText("Save again as " + act->text());
+ ui.FinalRenderSaveAgainAsButton->setText("Save Again as " + act->text());
ui.FinalRenderSaveAgainAsButton->setProperty("tag", act->text());
}
}
diff --git a/Source/Fractorium/FinalRenderDialog.ui b/Source/Fractorium/FinalRenderDialog.ui
index 135920e..bdfecd4 100644
--- a/Source/Fractorium/FinalRenderDialog.ui
+++ b/Source/Fractorium/FinalRenderDialog.ui
@@ -1194,6 +1194,9 @@
-
+
+ <html><head/><body><p>Save the rendered image again using the specified file type.</p><p>This will copy in the values for Brightness, Gamma, Gamma Threshold, Vibrancy, Highlight Power, K2, Spatial Filter Type/Width, MinDE, MaxDE and CurveDE from the main window, and if any have changed, it will perform the filtering and imaging steps of the rendering process again before saving.</p><p>The values will not be copied from the main window if Strips is greater than 1.</p></body></html>
+
Save Again As
@@ -1207,6 +1210,9 @@
-
+
+ <html><head/><body><p>Render with the additional quality specified, picking up where the last render left off.</p><p>This will copy in the values for Brightness, Gamma, Gamma Threshold, Vibrancy, Highlight Power, K2, Spatial Filter Type/Width, MinDE, MaxDE and CurveDE from the main window and will apply them in the filtering and imaging steps of the rendering process.</p></body></html>
+
Add Quality
diff --git a/Source/Fractorium/FinalRenderEmberController.cpp b/Source/Fractorium/FinalRenderEmberController.cpp
index 70931d0..b3b966e 100644
--- a/Source/Fractorium/FinalRenderEmberController.cpp
+++ b/Source/Fractorium/FinalRenderEmberController.cpp
@@ -118,6 +118,7 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD
m_FinishedImageCount.store(0);
Pause(false);
ResetProgress();
+ FirstOrDefaultRenderer()->m_ProgressParameter = reinterpret_cast(¤tStripForProgress);//When animating, only the first (primary) device has a progress parameter.
if (!isBump)
{
@@ -128,7 +129,6 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD
m_XmlWriter.Save(backup.toStdString().c_str(), *m_Ember, 0, true, false, true, false, 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,
[&](const string & s) { Output(QString::fromStdString(s)); }, //Greater than height.
[&](const string & s) { Output(QString::fromStdString(s)); }, //Mod height != 0.
@@ -297,7 +297,7 @@ FinalRenderEmberController::FinalRenderEmberController(FractoriumFinalRenderD
{
m_ImageCount = 1;
m_Ember->m_TemporalSamples = 1;
- m_Fractorium->m_Controller->ParamsToEmber(*m_Ember, true); // update color and filter params
+ m_Fractorium->m_Controller->ParamsToEmber(*m_Ember, true);//Update color and filter params from the main window controls, which only affect the filter and/or final accumulation stage.
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();
@@ -750,21 +750,61 @@ EmberNs::Renderer* FinalRenderEmberController::FirstOrDefaultRender
///
/// Save the output of the last rendered image using the existing image output buffer in the renderer.
+/// Before rendering, this copies the image coloring/filtering values used in the last step of the rendering
+/// process, and performs that part of the render, before saving.
///
/// The full path and filename the image was saved to.
template
QString FinalRenderEmberController::SaveCurrentAgain()
{
- if (!m_Ember)
- return "";
+ if (!m_Ember)
+ return "";
- m_Fractorium->m_Controller->ParamsToEmber(*m_Ember, true); // update color and filter params
- m_Run = true;
- m_Ember->m_TemporalSamples = 1;
- m_Renderer->SetEmber(*m_Ember, eProcessAction::FILTER_AND_ACCUM);
- m_Renderer->Run(m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp);
- m_Run = false;
- return SaveCurrentRender(*m_Ember);
+ if (m_GuiState.m_Strips == 1)
+ {
+ size_t currentStripForProgress = 0;
+ auto brightness = m_Ember->m_Brightness;
+ auto gamma = m_Ember->m_Gamma;
+ auto gammathresh = m_Ember->m_GammaThresh;
+ auto vibrancy = m_Ember->m_Vibrancy;
+ auto highlight = m_Ember->m_HighlightPower;
+ auto k2 = m_Ember->m_K2;
+ auto sftype = m_Ember->m_SpatialFilterType;
+ auto sfradius = m_Ember->m_SpatialFilterRadius;
+ auto minde = m_Ember->m_MinRadDE;
+ auto maxde = m_Ember->m_MaxRadDE;
+ auto curvede = m_Ember->m_CurveDE;
+ m_Fractorium->m_Controller->ParamsToEmber(*m_Ember, true);//Update color and filter params from the main window controls, which only affect the filter and/or final accumulation stage.
+ auto dofilterandaccum = m_GuiState.m_EarlyClip ||
+ brightness != m_Ember->m_Brightness ||
+ k2 != m_Ember->m_K2 ||
+ minde != m_Ember->m_MinRadDE ||
+ maxde != m_Ember->m_MaxRadDE ||
+ curvede != m_Ember->m_CurveDE;
+
+ //This is sort of a hack outside of the normal rendering process above.
+ if (dofilterandaccum ||
+ gamma != m_Ember->m_Gamma ||
+ gammathresh != m_Ember->m_GammaThresh ||
+ vibrancy != m_Ember->m_Vibrancy ||
+ highlight != m_Ember->m_HighlightPower ||
+ sftype != m_Ember->m_SpatialFilterType ||
+ sfradius != m_Ember->m_SpatialFilterRadius
+ )
+ {
+ m_Run = true;
+ m_FinishedImageCount.store(0);
+ m_Ember->m_TemporalSamples = 1;
+ m_Renderer->m_ProgressParameter = reinterpret_cast(¤tStripForProgress);//Need to reset this because it was set to a local variable within the render thread.
+ m_Renderer->SetEmber(*m_Ember, dofilterandaccum ? eProcessAction::FILTER_AND_ACCUM : eProcessAction::ACCUM_ONLY);
+ m_Renderer->Run(m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp);
+ m_FinishedImageCount.fetch_add(1);
+ HandleFinishedProgress();
+ m_Run = false;
+ }
+ }
+
+ return SaveCurrentRender(*m_Ember);
}
///
@@ -868,7 +908,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.FinalRenderSaveAgainAsButton, "setEnabled", Qt::QueuedConnection, Q_ARG(bool, !doAll && m_Renderer.get() && m_GuiState.m_Strips == 1));
+ QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderSaveAgainAsButton, "setEnabled", Qt::QueuedConnection, Q_ARG(bool, !doAll && m_Renderer.get()));//Can do save again with variable number of strips.
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/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h
index 1e3f087..2885d2c 100644
--- a/Source/Fractorium/FractoriumEmberController.h
+++ b/Source/Fractorium/FractoriumEmberController.h
@@ -139,9 +139,9 @@ public:
virtual void SequenceOpenButtonClicked() { }
//Params.
- virtual void ParamsToEmber(Ember& ember, bool basicParams = false) { };
+ virtual void ParamsToEmber(Ember& ember, bool imageParamsOnly = false) { };
#ifdef DO_DOUBLE
- virtual void ParamsToEmber(Ember& ember, bool basicParams = false) { };
+ virtual void ParamsToEmber(Ember& ember, bool imageParamsOnly = false) { };
#endif
virtual void SetCenter(double x, double y) { }
virtual void FillParamTablesAndPalette() { }
@@ -425,9 +425,9 @@ public:
virtual void SequenceOpenButtonClicked() override;
//Params.
- virtual void ParamsToEmber(Ember& ember, bool basicParams = false) override;
+ virtual void ParamsToEmber(Ember& ember, bool imageParamsOnly = false) override;
#ifdef DO_DOUBLE
- virtual void ParamsToEmber(Ember& ember, bool basicParams = false) override;
+ virtual void ParamsToEmber(Ember& ember, bool imageParamsOnly = false) override;
#endif
virtual void SetCenter(double x, double y) override;
virtual void FillParamTablesAndPalette() override;
@@ -566,7 +566,7 @@ private:
template void SetEmberPrivate(const Ember& ember, bool verbatim, bool updatePointer);
//Params.
- template void ParamsToEmberPrivate(Ember& ember, bool basicParams);
+ template void ParamsToEmberPrivate(Ember& ember, bool imageParamsOnly);
//Xforms.
void SetNormalizedWeightText(Xform* xform);
diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp
index 7d7c6b1..64c2388 100644
--- a/Source/Fractorium/FractoriumParams.cpp
+++ b/Source/Fractorium/FractoriumParams.cpp
@@ -828,57 +828,57 @@ void FractoriumEmberController::FillParamTablesAndPalette()
/// Copy all GUI widget values on the parameters tab to the passed in ember.
///
/// The ember to copy values to.
-/// true to get just filter and colors.
-template void FractoriumEmberController::ParamsToEmber(Ember& ember, bool basicParams) { ParamsToEmberPrivate(ember, basicParams); }
+/// True to get just spatial and density filters plus coloring params.
+template void FractoriumEmberController::ParamsToEmber(Ember& ember, bool imageParamsOnly) { ParamsToEmberPrivate(ember, imageParamsOnly); }
#ifdef DO_DOUBLE
-template void FractoriumEmberController::ParamsToEmber(Ember& ember, bool basicParams) { ParamsToEmberPrivate(ember, basicParams); }
+template void FractoriumEmberController::ParamsToEmber(Ember& ember, bool imageParamsOnly) { ParamsToEmberPrivate(ember, imageParamsOnly); }
#endif
template
template
-void FractoriumEmberController::ParamsToEmberPrivate(Ember& ember, bool basicParams)
+void FractoriumEmberController::ParamsToEmberPrivate(Ember& ember, bool imageParamsOnly)
{
- ember.m_Brightness = m_Fractorium->m_BrightnessSpin->value();//Color.
- ember.m_Gamma = m_Fractorium->m_GammaSpin->value();
- ember.m_GammaThresh = m_Fractorium->m_GammaThresholdSpin->value();
- ember.m_Vibrancy = m_Fractorium->m_VibrancySpin->value();
- ember.m_HighlightPower = m_Fractorium->m_HighlightSpin->value();
- ember.m_K2 = m_Fractorium->m_K2Spin->value();
- ember.m_SpatialFilterRadius = m_Fractorium->m_SpatialFilterWidthSpin->value();//Filter.
- ember.m_SpatialFilterType = eSpatialFilterType(m_Fractorium->m_SpatialFilterTypeCombo->currentIndex());
- ember.m_TemporalFilterWidth = m_Fractorium->m_TemporalFilterWidthSpin->value();
- ember.m_TemporalFilterType = eTemporalFilterType(m_Fractorium->m_TemporalFilterTypeCombo->currentIndex());
- ember.m_MinRadDE = m_Fractorium->m_DEFilterMinRadiusSpin->value();
- ember.m_MaxRadDE = m_Fractorium->m_DEFilterMaxRadiusSpin->value();
- ember.m_CurveDE = m_Fractorium->m_DECurveSpin->value();
+ ember.m_Brightness = m_Fractorium->m_BrightnessSpin->value();//Color.
+ ember.m_Gamma = m_Fractorium->m_GammaSpin->value();
+ ember.m_GammaThresh = m_Fractorium->m_GammaThresholdSpin->value();
+ ember.m_Vibrancy = m_Fractorium->m_VibrancySpin->value();
+ ember.m_HighlightPower = m_Fractorium->m_HighlightSpin->value();
+ ember.m_K2 = m_Fractorium->m_K2Spin->value();
+ ember.m_SpatialFilterRadius = m_Fractorium->m_SpatialFilterWidthSpin->value();//Filter.
+ ember.m_SpatialFilterType = eSpatialFilterType(m_Fractorium->m_SpatialFilterTypeCombo->currentIndex());
+ ember.m_MinRadDE = m_Fractorium->m_DEFilterMinRadiusSpin->value();
+ ember.m_MaxRadDE = m_Fractorium->m_DEFilterMaxRadiusSpin->value();
+ ember.m_CurveDE = m_Fractorium->m_DECurveSpin->value();
- if(basicParams)
- return;
+ if (imageParamsOnly)
+ return;
- auto color = m_Fractorium->ui.ColorTable->item(5, 1)->backgroundColor();
- ember.m_Background.r = color.red() / 255.0;
- ember.m_Background.g = color.green() / 255.0;
- ember.m_Background.b = color.blue() / 255.0;
- ember.m_PaletteMode = ePaletteMode(m_Fractorium->m_PaletteModeCombo->currentIndex());
- ember.m_FinalRasW = m_Fractorium->m_WidthSpin->value();//Geometry.
- ember.m_FinalRasH = m_Fractorium->m_HeightSpin->value();
- ember.m_CenterX = m_Fractorium->m_CenterXSpin->value();
- ember.m_CenterY = ember.m_RotCenterY = m_Fractorium->m_CenterYSpin->value();
- ember.m_PixelsPerUnit = m_Fractorium->m_ScaleSpin->value();
- ember.m_Zoom = m_Fractorium->m_ZoomSpin->value();
- ember.m_Rotate = m_Fractorium->m_RotateSpin->value();
- ember.m_CamZPos = m_Fractorium->m_ZPosSpin->value();
- ember.m_CamPerspective = m_Fractorium->m_PerspectiveSpin->value();
- ember.m_CamPitch = m_Fractorium->m_PitchSpin->value() * DEG_2_RAD_T;
- ember.m_CamYaw = m_Fractorium->m_YawSpin->value() * DEG_2_RAD_T;
- ember.m_CamDepthBlur = m_Fractorium->m_DepthBlurSpin->value();
- ember.m_SubBatchSize = m_Fractorium->m_SbsSpin->value();
- ember.m_FuseCount = m_Fractorium->m_FuseSpin->value();
- ember.m_RandPointRange = m_Fractorium->m_RandRangeSpin->value();
- ember.m_Quality = m_Fractorium->m_QualitySpin->value();
- ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();
- ember.m_AffineInterp = eAffineInterp(m_Fractorium->m_AffineInterpTypeCombo->currentIndex());
- ember.m_Interp = eInterp(m_Fractorium->m_InterpTypeCombo->currentIndex());
- ember.SyncSize();
+ ember.m_TemporalFilterWidth = m_Fractorium->m_TemporalFilterWidthSpin->value();
+ ember.m_TemporalFilterType = eTemporalFilterType(m_Fractorium->m_TemporalFilterTypeCombo->currentIndex());
+ auto color = m_Fractorium->ui.ColorTable->item(5, 1)->backgroundColor();
+ ember.m_Background.r = color.red() / 255.0;
+ ember.m_Background.g = color.green() / 255.0;
+ ember.m_Background.b = color.blue() / 255.0;
+ ember.m_PaletteMode = ePaletteMode(m_Fractorium->m_PaletteModeCombo->currentIndex());
+ ember.m_FinalRasW = m_Fractorium->m_WidthSpin->value();//Geometry.
+ ember.m_FinalRasH = m_Fractorium->m_HeightSpin->value();
+ ember.m_CenterX = m_Fractorium->m_CenterXSpin->value();
+ ember.m_CenterY = ember.m_RotCenterY = m_Fractorium->m_CenterYSpin->value();
+ ember.m_PixelsPerUnit = m_Fractorium->m_ScaleSpin->value();
+ ember.m_Zoom = m_Fractorium->m_ZoomSpin->value();
+ ember.m_Rotate = m_Fractorium->m_RotateSpin->value();
+ ember.m_CamZPos = m_Fractorium->m_ZPosSpin->value();
+ ember.m_CamPerspective = m_Fractorium->m_PerspectiveSpin->value();
+ ember.m_CamPitch = m_Fractorium->m_PitchSpin->value() * DEG_2_RAD_T;
+ ember.m_CamYaw = m_Fractorium->m_YawSpin->value() * DEG_2_RAD_T;
+ ember.m_CamDepthBlur = m_Fractorium->m_DepthBlurSpin->value();
+ ember.m_SubBatchSize = m_Fractorium->m_SbsSpin->value();
+ ember.m_FuseCount = m_Fractorium->m_FuseSpin->value();
+ ember.m_RandPointRange = m_Fractorium->m_RandRangeSpin->value();
+ ember.m_Quality = m_Fractorium->m_QualitySpin->value();
+ ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();
+ ember.m_AffineInterp = eAffineInterp(m_Fractorium->m_AffineInterpTypeCombo->currentIndex());
+ ember.m_Interp = eInterp(m_Fractorium->m_InterpTypeCombo->currentIndex());
+ ember.SyncSize();
}
///