diff --git a/Builds/MSVC/Installer/FractoriumInstaller.wixproj b/Builds/MSVC/Installer/FractoriumInstaller.wixproj
index 87b6ffd..4951f58 100644
--- a/Builds/MSVC/Installer/FractoriumInstaller.wixproj
+++ b/Builds/MSVC/Installer/FractoriumInstaller.wixproj
@@ -6,7 +6,7 @@
3.7
{c8096c47-e358-438c-a520-146d46b0637d}
2.0
- Fractorium_Beta_0.4.1.3
+ Fractorium_Beta_0.4.1.4
Package
$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets
$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets
diff --git a/Builds/MSVC/Installer/Product.wxs b/Builds/MSVC/Installer/Product.wxs
index 728785d..83f5a8d 100644
--- a/Builds/MSVC/Installer/Product.wxs
+++ b/Builds/MSVC/Installer/Product.wxs
@@ -1,6 +1,6 @@
-
+
diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h
index 7742c1d..b479350 100644
--- a/Source/Ember/Ember.h
+++ b/Source/Ember/Ember.h
@@ -93,7 +93,6 @@ public:
m_OrigFinalRasH = ember.m_OrigFinalRasH;
m_OrigPixPerUnit = ember.m_OrigPixPerUnit;
m_Supersample = ember.m_Supersample;
- m_Passes = ember.m_Passes;
m_TemporalSamples = ember.m_TemporalSamples;
m_Symmetry = ember.m_Symmetry;
@@ -186,7 +185,6 @@ public:
m_OrigFinalRasH = 1080;
m_OrigPixPerUnit = 240;
m_Supersample = 1;
- m_Passes = 1;
m_TemporalSamples = 1000;
m_Symmetry = 0;
m_Quality = 100;
@@ -778,7 +776,6 @@ public:
InterpT<&Ember::m_CamDepthBlur>(embers, coefs, size);
InterpX::m_CamMat>(embers, coefs, size);
InterpT<&Ember::m_Rotate>(embers, coefs, size);
- InterpI<&Ember::m_Passes>(embers, coefs, size);
InterpI<&Ember::m_TemporalSamples>(embers, coefs, size);
InterpT<&Ember::m_MaxRadDE>(embers, coefs, size);
InterpT<&Ember::m_MinRadDE>(embers, coefs, size);
@@ -1309,7 +1306,6 @@ public:
m_MinRadDE = 0;
m_CurveDE = T(0.4);
m_GammaThresh = T(0.01);
- m_Passes = 1;
m_TemporalSamples = 1000;
m_SpatialFilterType = GAUSSIAN_SPATIAL_FILTER;
m_AffineInterp = INTERP_LOG;
@@ -1341,7 +1337,6 @@ public:
m_MinRadDE = -1;
m_CurveDE = -1;
m_GammaThresh = -1;
- m_Passes = 0;
m_TemporalSamples = 0;
m_SpatialFilterType = GAUSSIAN_SPATIAL_FILTER;
m_AffineInterp = INTERP_LOG;
@@ -1381,7 +1376,6 @@ public:
<< "Original Raster Width: " << m_OrigFinalRasW << endl
<< "Original Raster Height: " << m_OrigFinalRasH << endl
<< "Supersample: " << m_Supersample << endl
- << "Passes: " << m_Passes << endl
<< "Temporal Samples: " << m_TemporalSamples << endl
<< "Symmetry: " << m_Symmetry << endl
@@ -1468,11 +1462,7 @@ public:
//The multiplier in size of the histogram and DE filtering buffers. Must be at least one, preferrably never larger than 4, only useful at 2.
//Xml field: "supersample" or "overample (deprecated)".
size_t m_Supersample;
-
- //Times to run the algorithm while clearing the histogram, but not the filter. Almost always set to 1 and may even be deprecated.
- //Xml field: "passes".
- size_t m_Passes;
-
+
//When animating, split each pass into this many pieces, each doing a fraction of the total iterations. Each temporal sample
//will render an interpolated instance of the ember that is a fraction of the current ember and the next one.
//When rendering a single image, this field is always set to 1.
diff --git a/Source/Ember/EmberDefines.h b/Source/Ember/EmberDefines.h
index 452944e..6adb8eb 100644
--- a/Source/Ember/EmberDefines.h
+++ b/Source/Ember/EmberDefines.h
@@ -36,7 +36,7 @@ namespace EmberNs
extern void sincos(float x, float *s, float *c);
#endif
-#define EMBER_VERSION "0.4.1.3"
+#define EMBER_VERSION "0.4.1.4"
#define EPS6 T(1e-6)
#define EPS std::numeric_limits::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way.
#define ISAAC_SIZE 4
diff --git a/Source/Ember/EmberToXml.h b/Source/Ember/EmberToXml.h
index e949f12..f345279 100644
--- a/Source/Ember/EmberToXml.h
+++ b/Source/Ember/EmberToXml.h
@@ -155,7 +155,6 @@ public:
os << " temporal_filter_width=\"" << ember.m_TemporalFilterWidth << "\"";
os << " quality=\"" << ember.m_Quality << "\"";
- os << " passes=\"" << ember.m_Passes << "\"";
os << " temporal_samples=\"" << ember.m_TemporalSamples << "\"";
os << " background=\"" << ember.m_Background.r << " " << ember.m_Background.g << " " << ember.m_Background.b << "\"";
os << " brightness=\"" << ember.m_Brightness << "\"";
diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp
index f0d7ae4..afe8619 100644
--- a/Source/Ember/Renderer.cpp
+++ b/Source/Ember/Renderer.cpp
@@ -265,14 +265,13 @@ bool Renderer::CreateTemporalFilter(bool& newAlloc)
//Use intelligent testing so it isn't created every time a new ember is passed in.
if ((!m_TemporalFilter.get()) ||
- (m_Ember.m_Passes != m_TemporalFilter->Passes()) ||
(m_Ember.m_TemporalSamples != m_TemporalFilter->TemporalSamples()) ||
(m_Ember.m_TemporalFilterType != m_TemporalFilter->FilterType()) ||
(m_Ember.m_TemporalFilterWidth != m_TemporalFilter->FilterWidth()) ||
(m_Ember.m_TemporalFilterExp != m_TemporalFilter->FilterExp()))
{
m_TemporalFilter = unique_ptr>(
- TemporalFilterCreator::Create(m_Ember.m_TemporalFilterType, m_Ember.m_Passes, m_Ember.m_TemporalSamples, m_Ember.m_TemporalFilterWidth, m_Ember.m_TemporalFilterExp));
+ TemporalFilterCreator::Create(m_Ember.m_TemporalFilterType, m_Ember.m_TemporalSamples, m_Ember.m_TemporalFilterWidth, m_Ember.m_TemporalFilterExp));
newAlloc = true;
}
@@ -287,15 +286,13 @@ bool Renderer::CreateTemporalFilter(bool& newAlloc)
/// future-proofs the algorithm for GPU-based renderers.
/// If the caller calls Abort() at any time, or the progress function returns 0,
/// the entire rendering process will exit as soon as it can.
+/// The concept of passes from flam3 has been removed as it was never used.
/// The loop structure is:
/// {
-/// Passes (Default 1)
+/// Temporal Samples (Default 1 for single image)
/// {
-/// Temporal Samples (Default 1 for single image)
+/// Iterate (Either to completion or to a specified number of iterations)
/// {
-/// Iterate (Either to completion or to a specified number of iterations)
-/// {
-/// }
/// }
/// }
///
@@ -326,11 +323,11 @@ eRenderStatus Renderer::Run(vector& finalImage, doubl
m_InRender = true;
EnterRender();
m_Abort = false;
- bool filterAndAccumOnly = (m_ProcessAction == FILTER_AND_ACCUM && Passes() == 1);
+ bool filterAndAccumOnly = m_ProcessAction == FILTER_AND_ACCUM;
bool accumOnly = m_ProcessAction == ACCUM_ONLY;
bool resume = m_ProcessState != NONE;
bool newFilterAlloc;
- size_t temporalSample = 0, pass;
+ size_t temporalSample = 0;
T deTime;
eRenderStatus success = RENDER_OK;
//double iterationTime = 0;
@@ -349,7 +346,6 @@ eRenderStatus Renderer::Run(vector& finalImage, doubl
if (!resume)//Beginning, reset everything.
{
- m_LastPass = 0;
m_LastTemporalSample = 0;
m_LastIter = 0;
m_LastIterPercent = 0;
@@ -360,9 +356,8 @@ eRenderStatus Renderer::Run(vector& finalImage, doubl
m_Background.Clear();
}
//User requested an increase in quality after finishing.
- else if (m_ProcessState == ITER_STARTED && m_ProcessAction == KEEP_ITERATING && TemporalSamples() == 1 && Passes() == 1)
+ else if (m_ProcessState == ITER_STARTED && m_ProcessAction == KEEP_ITERATING && TemporalSamples() == 1)
{
- m_LastPass = 0;
m_LastTemporalSample = 0;
m_LastIter = m_Stats.m_Iters;
m_LastIterPercent = 0;//Might skip a progress update, but shouldn't matter.
@@ -372,10 +367,7 @@ eRenderStatus Renderer::Run(vector& finalImage, doubl
m_Background.Clear();
}
- pass = (resume ? m_LastPass : 0);
-
//Make sure values are within valid range.
- ClampGteRef(m_Ember.m_Passes, size_t(1));
ClampGteRef(m_Ember.m_Supersample, size_t(1));
//Make sure to get most recent update since loop won't be entered to call Interp().
@@ -426,199 +418,176 @@ eRenderStatus Renderer::Run(vector& finalImage, doubl
if (!resume)
ResetBuckets(true, false);//Only reset hist here and do accum when needed later on.
- //Passes, outermost loop 1.
- for (; (pass < Passes()) && !m_Abort;)
- {
- deTime = T(time) + m_TemporalFilter->Deltas()[pass * m_Ember.m_TemporalSamples];
+ deTime = T(time) + m_TemporalFilter->Deltas()[0];
- //Interpolate and get an ember for DE purposes.
- //Additional interpolation will be done in the temporal samples loop.
+ //Interpolate and get an ember for DE purposes.
+ //Additional interpolation will be done in the temporal samples loop.
+ //it.Tic();
+ if (m_Embers.size() > 1)
+ Interpolater::Interpolate(m_Embers, deTime, 0, m_Ember);
+ //it.Toc("Interp 2");
+
+ ClampGte(m_Ember.m_MinRadDE, 0);
+ ClampGte(m_Ember.m_MaxRadDE, 0);
+
+ if (!CreateDEFilter(newFilterAlloc))
+ {
+ m_ErrorReport.push_back("Density filter creation failed, aborting.\n");
+ success = RENDER_ERROR;
+ goto Finish;
+ }
+
+ //Temporal samples, loop 1.
+ temporalSample = resume ? m_LastTemporalSample : 0;
+ for (; (temporalSample < TemporalSamples()) && !m_Abort;)
+ {
+ T colorScalar = m_TemporalFilter->Filter()[temporalSample];
+ T temporalTime = T(time) + m_TemporalFilter->Deltas()[temporalSample];
+
+ //Interpolate again.
//it.Tic();
if (m_Embers.size() > 1)
- Interpolater::Interpolate(m_Embers, deTime, 0, m_Ember);
- //it.Toc("Interp 2");
+ Interpolater::Interpolate(m_Embers, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
- ClampGte(m_Ember.m_MinRadDE, 0);
- ClampGte(m_Ember.m_MaxRadDE, 0);
+ //it.Toc("Interp 3");
- if (!CreateDEFilter(newFilterAlloc))
+ if (!resume && !AssignIterator())
{
- m_ErrorReport.push_back("Density filter creation failed, aborting.\n");
+ m_ErrorReport.push_back("Iterator assignment failed, aborting.\n");
success = RENDER_ERROR;
goto Finish;
}
- //Temporal samples, loop 2.
- temporalSample = resume ? m_LastTemporalSample : 0;
- for (; (temporalSample < TemporalSamples()) && !m_Abort;)
+ ComputeCamera();
+
+ //For each temporal sample, the palette m_Dmap needs to be re-created with color scalar. 1 if no temporal samples.
+ MakeDmap(colorScalar);
+
+ //The actual number of times to iterate. Each thread will get (totalIters / ThreadCount) iters to do.
+ //This is based on zoom and scale calculated in ComputeCamera().
+ //Note that the iter count is based on the final image dimensions, and not the super sampled dimensions.
+ size_t itersPerTemporalSample = ItersPerTemporalSample();//The total number of iterations for this temporal sample without overrides.
+ size_t sampleItersToDo;//The number of iterations to actually do in this sample, considering overrides.
+
+ if (subBatchCountOverride > 0)
+ sampleItersToDo = subBatchCountOverride * SubBatchSize() * ThreadCount();//Run a specific number of sub batches.
+ else
+ sampleItersToDo = itersPerTemporalSample;//Run as many iters as specified to complete this temporal sample.
+
+ sampleItersToDo = min(sampleItersToDo, itersPerTemporalSample - m_LastIter);
+ EmberStats stats = Iterate(sampleItersToDo, temporalSample);//The heavy work is done here.
+
+ //If no iters were executed, something went catastrophically wrong.
+ if (stats.m_Iters == 0)
{
- T colorScalar = m_TemporalFilter->Filter()[pass * TemporalSamples() + temporalSample];
- T temporalTime = T(time) + m_TemporalFilter->Deltas()[pass * TemporalSamples() + temporalSample];
-
- //Interpolate again.
- //it.Tic();
- if (m_Embers.size() > 1)
- Interpolater::Interpolate(m_Embers, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
-
- //it.Toc("Interp 3");
-
- if (!resume && !AssignIterator())
- {
- m_ErrorReport.push_back("Iterator assignment failed, aborting.\n");
- success = RENDER_ERROR;
- goto Finish;
- }
-
- ComputeCamera();
-
- //For each temporal sample, the palette m_Dmap needs to be re-created with color scalar. 1 if no temporal samples.
- MakeDmap(colorScalar);
-
- //The actual number of times to iterate. Each thread will get (totalIters / ThreadCount) iters to do.
- //This is based on zoom and scale calculated in ComputeCamera().
- //Note that the iter count is based on the final image dimensions, and not the super sampled dimensions.
- size_t itersPerTemporalSample = ItersPerTemporalSample();//The total number of iterations for this temporal sample in this pass without overrides.
- size_t sampleItersToDo;//The number of iterations to actually do in this sample in this pass, considering overrides.
-
- if (subBatchCountOverride > 0)
- sampleItersToDo = subBatchCountOverride * SubBatchSize() * ThreadCount();//Run a specific number of sub batches.
- else
- sampleItersToDo = itersPerTemporalSample;//Run as many iters as specified to complete this temporal sample.
-
- sampleItersToDo = min(sampleItersToDo, itersPerTemporalSample - m_LastIter);
- EmberStats stats = Iterate(sampleItersToDo, pass, temporalSample);//The heavy work is done here.
-
- //If no iters were executed, something went catastrophically wrong.
- if (stats.m_Iters == 0)
- {
- m_ErrorReport.push_back("Zero iterations ran, rendering failed, aborting.\n");
- success = RENDER_ERROR;
- Abort();
- goto Finish;
- }
-
- if (m_Abort)
- {
- success = RENDER_ABORT;
- goto Finish;
- }
-
- //Accumulate stats whether this batch ran to completion or exited prematurely.
- m_LastIter += stats.m_Iters;//Sum of iter count of all threads, reset each temporal sample.
- m_Stats.m_Iters += stats.m_Iters;//Sum of iter count of all threads, cumulative from beginning to end.
- m_Stats.m_Badvals += stats.m_Badvals;
- m_Stats.m_IterMs += stats.m_IterMs;
-
- //After each temporal sample, accumulate these.
- //Allow for incremental rendering by only taking action if the iter loop for this temporal sample is completely done.
- if (m_LastIter >= itersPerTemporalSample)
- {
- m_Vibrancy += m_Ember.m_Vibrancy;
- m_Gamma += m_Ember.m_Gamma;
- m_Background.r += m_Ember.m_Background.r;
- m_Background.g += m_Ember.m_Background.g;
- m_Background.b += m_Ember.m_Background.b;
- m_VibGamCount++;
- m_LastIter = 0;
- temporalSample++;
- }
-
- m_LastTemporalSample = temporalSample;
-
- if (subBatchCountOverride > 0)//Don't keep going through this loop if only doing an incremental render.
- break;
- }//Temporal samples.
-
- //If we've completed all temporal samples and all passes, then it was a complete render, so report progress.
- if ((Passes() == 1 || pass == Passes() - 1) && (temporalSample >= TemporalSamples()))
- {
- m_ProcessState = ITER_DONE;
-
- if (m_Callback && !m_Callback->ProgressFunc(m_Ember, m_ProgressParameter, 100.0, 0, 0))
- {
- Abort();
- success = RENDER_ABORT;
- goto Finish;
- }
+ m_ErrorReport.push_back("Zero iterations ran, rendering failed, aborting.\n");
+ success = RENDER_ERROR;
+ Abort();
+ goto Finish;
}
-FilterAndAccum:
- if (filterAndAccumOnly || temporalSample >= TemporalSamples() || forceOutput)
+ if (m_Abort)
{
- //t.Toc("Iterating and accumulating");
- //Compute k1 and k2.
- eRenderStatus fullRun = RENDER_OK;//Whether density filtering was run to completion without aborting prematurely or triggering an error.
- T passFilter = T(1) / T(Passes());//Original used an array, but every element in the array had the same value, so just use a single value here.
-
- T area = FinalRasW() * FinalRasH() / (m_PixelsPerUnitX * m_PixelsPerUnitY);//Need to use temps from field if ever implemented.
- m_K1 = (Brightness() * T(268.0) * passFilter) / 256;
-
- //When doing an interactive render, force output early on in the render process, before all iterations are done.
- //This presents a problem with the normal calculation of K2 since it relies on the quality value; it will scale the colors
- //to be very dark. Correct it by pretending the number of iters done is the exact quality desired and then scale according to that.
- if (forceOutput)
- {
- T quality = ((T)m_Stats.m_Iters / (T)FinalDimensions()) * (m_Scale * m_Scale);
- m_K2 = (Supersample() * Supersample() * Passes()) / (area * quality * m_TemporalFilter->SumFilt());
- }
- else
- m_K2 = (Supersample() * Supersample() * Passes()) / (area * m_ScaledQuality * m_TemporalFilter->SumFilt());
-
- if (filterAndAccumOnly || pass == 0)
- ResetBuckets(false, true);//Only the histogram was reset above, now reset the density filtering buffer.
- //t.Tic();
-
- //Apply appropriate filter if iterating is complete.
- if (filterAndAccumOnly || temporalSample >= TemporalSamples())
- {
- fullRun = m_DensityFilter.get() ? GaussianDensityFilter() : LogScaleDensityFilter();
- }
- else
- {
- //Apply requested filter for a forced output during interactive rendering.
- if (m_DensityFilter.get() && m_InteractiveFilter == FILTER_DE)
- fullRun = GaussianDensityFilter();
- else if (!m_DensityFilter.get() || m_InteractiveFilter == FILTER_LOG)
- fullRun = LogScaleDensityFilter();
- }
-
- //Only update state if iterating and filtering finished completely (didn't arrive here via forceOutput).
- if (fullRun == RENDER_OK && m_ProcessState == ITER_DONE && (Passes() == 1 || pass == Passes() - 1))
- m_ProcessState = FILTER_DONE;
-
- //Take special action if filtering exited prematurely.
- if (fullRun != RENDER_OK)
- {
- if (Passes() > 1)//Since all filtering is cummulative with passes > 1, must restart the entire process.
- {
- m_ProcessState = NONE;
- m_ProcessAction = FULL_RENDER;
- }
-
- ResetBuckets(false, true);//Reset the accumulator, come back and try again on the next call.
- success = fullRun;
- goto Finish;
- }
-
- if (m_Abort)
- {
- success = RENDER_ABORT;
- goto Finish;
- }
- //t.Toc("Density estimation filtering time: ", true);
+ success = RENDER_ABORT;
+ goto Finish;
}
- //Only increment pass if the temporal samples loop has been completed, which could have been done incrementally.
- //Also skip if rendering jumped straight here after completely finishing beforehand.
- if (!filterAndAccumOnly && temporalSample >= TemporalSamples())//This may not work if filtering was prematurely exited.
- pass++;
+ //Accumulate stats whether this batch ran to completion or exited prematurely.
+ m_LastIter += stats.m_Iters;//Sum of iter count of all threads, reset each temporal sample.
+ m_Stats.m_Iters += stats.m_Iters;//Sum of iter count of all threads, cumulative from beginning to end.
+ m_Stats.m_Badvals += stats.m_Badvals;
+ m_Stats.m_IterMs += stats.m_IterMs;
- if (!filterAndAccumOnly)
- m_LastPass = pass;
+ //After each temporal sample, accumulate these.
+ //Allow for incremental rendering by only taking action if the iter loop for this temporal sample is completely done.
+ if (m_LastIter >= itersPerTemporalSample)
+ {
+ m_Vibrancy += m_Ember.m_Vibrancy;
+ m_Gamma += m_Ember.m_Gamma;
+ m_Background.r += m_Ember.m_Background.r;
+ m_Background.g += m_Ember.m_Background.g;
+ m_Background.b += m_Ember.m_Background.b;
+ m_VibGamCount++;
+ m_LastIter = 0;
+ temporalSample++;
+ }
+
+ m_LastTemporalSample = temporalSample;
if (subBatchCountOverride > 0)//Don't keep going through this loop if only doing an incremental render.
break;
- }//Passes.
+ }//Temporal samples.
+
+ //If we've completed all temporal samples, then it was a complete render, so report progress.
+ if (temporalSample >= TemporalSamples())
+ {
+ m_ProcessState = ITER_DONE;
+
+ if (m_Callback && !m_Callback->ProgressFunc(m_Ember, m_ProgressParameter, 100.0, 0, 0))
+ {
+ Abort();
+ success = RENDER_ABORT;
+ goto Finish;
+ }
+ }
+
+FilterAndAccum:
+ if (filterAndAccumOnly || temporalSample >= TemporalSamples() || forceOutput)
+ {
+ //t.Toc("Iterating and accumulating");
+ //Compute k1 and k2.
+ eRenderStatus fullRun = RENDER_OK;//Whether density filtering was run to completion without aborting prematurely or triggering an error.
+
+ T area = FinalRasW() * FinalRasH() / (m_PixelsPerUnitX * m_PixelsPerUnitY);//Need to use temps from field if ever implemented.
+ m_K1 = (Brightness() * T(268.0)) / 256;
+
+ //When doing an interactive render, force output early on in the render process, before all iterations are done.
+ //This presents a problem with the normal calculation of K2 since it relies on the quality value; it will scale the colors
+ //to be very dark. Correct it by pretending the number of iters done is the exact quality desired and then scale according to that.
+ if (forceOutput)
+ {
+ T quality = ((T)m_Stats.m_Iters / (T)FinalDimensions()) * (m_Scale * m_Scale);
+ m_K2 = (Supersample() * Supersample()) / (area * quality * m_TemporalFilter->SumFilt());
+ }
+ else
+ m_K2 = (Supersample() * Supersample()) / (area * m_ScaledQuality * m_TemporalFilter->SumFilt());
+
+ ResetBuckets(false, true);//Only the histogram was reset above, now reset the density filtering buffer.
+ //t.Tic();
+
+ //Apply appropriate filter if iterating is complete.
+ if (filterAndAccumOnly || temporalSample >= TemporalSamples())
+ {
+ fullRun = m_DensityFilter.get() ? GaussianDensityFilter() : LogScaleDensityFilter();
+ }
+ else
+ {
+ //Apply requested filter for a forced output during interactive rendering.
+ if (m_DensityFilter.get() && m_InteractiveFilter == FILTER_DE)
+ fullRun = GaussianDensityFilter();
+ else if (!m_DensityFilter.get() || m_InteractiveFilter == FILTER_LOG)
+ fullRun = LogScaleDensityFilter();
+ }
+
+ //Only update state if iterating and filtering finished completely (didn't arrive here via forceOutput).
+ if (fullRun == RENDER_OK && m_ProcessState == ITER_DONE)
+ m_ProcessState = FILTER_DONE;
+
+ //Take special action if filtering exited prematurely.
+ if (fullRun != RENDER_OK)
+ {
+ ResetBuckets(false, true);//Reset the accumulator, come back and try again on the next call.
+ success = fullRun;
+ goto Finish;
+ }
+
+ if (m_Abort)
+ {
+ success = RENDER_ABORT;
+ goto Finish;
+ }
+ //t.Toc("Density estimation filtering time: ", true);
+ }
AccumOnly:
if (m_ProcessState == FILTER_DONE || forceOutput)
@@ -816,57 +785,29 @@ eRenderStatus Renderer::LogScaleDensityFilter()
//Timing t(4);
//Original didn't parallelize this, doing so gives a 50-75% speedup.
- //If there is only one pass, the value can be directly assigned, which is quicker than summing.
- if (Passes() == 1)
+ //The value can be directly assigned, which is quicker than summing.
+ parallel_for(startRow, endRow, [&] (size_t j)
{
- parallel_for(startRow, endRow, [&] (size_t j)
+ size_t row = j * m_SuperRasW;
+ //__m128 logm128;//Figure out SSE at some point.
+ //__m128 bucketm128;
+ //__m128 scaledBucket128;
+
+ for (size_t i = startCol; (i < endCol) && !m_Abort; i++)
{
- size_t row = j * m_SuperRasW;
- //__m128 logm128;//Figure out SSE at some point.
- //__m128 bucketm128;
- //__m128 scaledBucket128;
+ size_t index = row + i;
- for (size_t i = startCol; (i < endCol) && !m_Abort; i++)
+ //Check for visibility first before doing anything else to avoid all possible unnecessary calculations.
+ if (m_HistBuckets[index].a != 0)
{
- size_t index = row + i;
+ T logScale = (m_K1 * log(1 + m_HistBuckets[index].a * m_K2)) / m_HistBuckets[index].a;
- //Check for visibility first before doing anything else to avoid all possible unnecessary calculations.
- if (m_HistBuckets[index].a != 0)
- {
- T logScale = (m_K1 * log(1 + m_HistBuckets[index].a * m_K2)) / m_HistBuckets[index].a;
-
- //Original did a temporary assignment, then *= logScale, then passed the result to bump_no_overflow().
- //Combine here into one operation for a slight speedup.
- m_AccumulatorBuckets[index] = (m_HistBuckets[index] * (bucketT)logScale);
- }
+ //Original did a temporary assignment, then *= logScale, then passed the result to bump_no_overflow().
+ //Combine here into one operation for a slight speedup.
+ m_AccumulatorBuckets[index] = m_HistBuckets[index] * (bucketT)logScale;
}
- });
- }
- else//Passes > 1, so sum.
- {
- parallel_for(startRow, endRow, [&] (size_t j)
- {
- size_t row = j * m_SuperRasW;
-
- for (size_t i = startCol; (i < endCol) && !m_Abort; i++)
- {
- size_t index = row + i;
-
- //Check for visibility first before doing anything else to avoid all possible unnecessary calculations.
- if (m_HistBuckets[index].a != 0)
- {
- //Figure out SSE at some point.
- //__declspec(align(16))
- T logScale = (m_K1 * log(1 + m_HistBuckets[index].a * m_K2)) / m_HistBuckets[index].a;
- //logm128 = _mm_load1_ps(&logScale);
- //bucketm128 = _mm_load_ps(m_HistBuckets[index].Channels);
- //scaledBucket128 = _mm_mul_ps(logm128, bucketm128);
-
- m_AccumulatorBuckets[index] += (m_HistBuckets[index] * bucketT(logScale));
- }
- }
- });
- }
+ }
+ });
//t.Toc(__FUNCTION__);
return m_Abort ? RENDER_ABORT : RENDER_OK;
@@ -1216,11 +1157,10 @@ eRenderStatus Renderer::AccumulatorToFinalImage(unsigned char* pixel
/// which by default is 10,000 iterations.
///
/// The number of iterations to run
-/// The pass this is running for
-/// The temporal sample within the current pass this is running for
+/// The temporal sample this is running for
/// Rendering statistics
template
-EmberStats Renderer::Iterate(size_t iterCount, size_t pass, size_t temporalSample)
+EmberStats Renderer::Iterate(size_t iterCount, size_t temporalSample)
{
//Timing t2(4);
m_IterTimer.Tic();
@@ -1245,7 +1185,7 @@ EmberStats Renderer::Iterate(size_t iterCount, size_t pass, size_t t
m_BadVals[threadIndex] = 0;
- //Sub batch iterations, loop 3.
+ //Sub batch iterations, loop 2.
for (m_SubBatch[threadIndex] = 0; (m_SubBatch[threadIndex] < totalItersPerThread) && !m_Abort; m_SubBatch[threadIndex] += subBatchSize)
{
//Must recalculate the number of iters to run on each sub batch because the last batch will most likely have less than m_SubBatchSize iters.
@@ -1262,7 +1202,7 @@ EmberStats Renderer::Iterate(size_t iterCount, size_t pass, size_t t
//Finally, iterate.
//t.Tic();
- //Iterating, loop 4.
+ //Iterating, loop 3.
m_BadVals[threadIndex] += m_Iterator->Iterate(m_Ember, subBatchSize, fuse, m_Samples[threadIndex].data(), m_Rand[threadIndex]);
//iterationTime += t.Toc();
@@ -1278,21 +1218,19 @@ EmberStats Renderer::Iterate(size_t iterCount, size_t pass, size_t t
if (m_Callback && threadIndex == 0)
{
percent = 100.0 *
+
+ double
+ (
double
(
double
(
- double
- (
- double
- (
- //Takes progress of current thread and multiplies by thread count.
- //This assumes the threads progress at roughly the same speed.
- double(m_LastIter + (m_SubBatch[threadIndex] * m_ThreadsToUse)) / double(ItersPerTemporalSample())
- ) + temporalSample
- ) / (double)TemporalSamples()
- ) + (double)pass
- ) / (double)Passes();
+ //Takes progress of current thread and multiplies by thread count.
+ //This assumes the threads progress at roughly the same speed.
+ double(m_LastIter + (m_SubBatch[threadIndex] * m_ThreadsToUse)) / double(ItersPerTemporalSample())
+ ) + temporalSample
+ ) / (double)TemporalSamples()
+ );
double percentDiff = percent - m_LastIterPercent;
double toc = m_ProgressTimer.Toc();
@@ -1406,7 +1344,6 @@ template ePaletteMode Renderer::
/// Virtual ember wrappers overridden from RendererBase, getters only.
///
-template size_t Renderer::Passes() const { return m_Ember.m_Passes; }
template size_t Renderer::TemporalSamples() const { return m_Ember.m_TemporalSamples; }
template size_t Renderer::FinalRasW() const { return m_Ember.m_FinalRasW; }
template size_t Renderer::FinalRasH() const { return m_Ember.m_FinalRasH; }
diff --git a/Source/Ember/Renderer.h b/Source/Ember/Renderer.h
index 80494f5..8772eb1 100644
--- a/Source/Ember/Renderer.h
+++ b/Source/Ember/Renderer.h
@@ -74,7 +74,7 @@ protected:
virtual eRenderStatus GaussianDensityFilter();
virtual eRenderStatus AccumulatorToFinalImage(vector& pixels, size_t finalOffset);
virtual eRenderStatus AccumulatorToFinalImage(unsigned char* pixels, size_t finalOffset);
- virtual EmberStats Iterate(size_t iterCount, size_t pass, size_t temporalSample);
+ virtual EmberStats Iterate(size_t iterCount, size_t temporalSample);
public:
//Non-virtual render properties, getters and setters.
@@ -131,7 +131,6 @@ public:
inline ePaletteMode PaletteMode() const;
//Virtual ember wrappers overridden from RendererBase, getters only.
- virtual size_t Passes() const override;
virtual size_t TemporalSamples() const override;
virtual size_t FinalRasW() const override;
virtual size_t FinalRasH() const override;
diff --git a/Source/Ember/RendererBase.cpp b/Source/Ember/RendererBase.cpp
index 8b14263..2a4c9df 100644
--- a/Source/Ember/RendererBase.cpp
+++ b/Source/Ember/RendererBase.cpp
@@ -23,7 +23,6 @@ RendererBase::RendererBase()
ThreadCount(Timing::ProcessorCount());
m_Callback = nullptr;
m_ProgressParameter = nullptr;
- m_LastPass = 0;
m_LastTemporalSample = 0;
m_LastIter = 0;
m_LastIterPercent = 0;
@@ -65,7 +64,7 @@ void RendererBase::ChangeVal(std::function func, eProcessAction acti
//new and old quality values.
else if (action == KEEP_ITERATING)
{
- if (m_ProcessState == ACCUM_DONE && TemporalSamples() == 1 && Passes() == 1)
+ if (m_ProcessState == ACCUM_DONE && TemporalSamples() == 1)
{
m_ProcessState = ITER_STARTED;
m_ProcessAction = KEEP_ITERATING;
@@ -84,11 +83,11 @@ void RendererBase::ChangeVal(std::function func, eProcessAction acti
m_ProcessState = NONE;
m_ProcessAction = FULL_RENDER;
}
- //If passes == 1, set the state to ITER_DONE and the next process action to FILTER_AND_ACCUM.
+ //Set the state to ITER_DONE and the next process action to FILTER_AND_ACCUM.
else
{
- m_ProcessState = Passes() == 1 ? ITER_DONE : NONE;
- m_ProcessAction = Passes() == 1 ? FILTER_AND_ACCUM : FULL_RENDER;//Cannot just filter if passes > 1 because filtering is done with each pass.
+ m_ProcessState = ITER_DONE;
+ m_ProcessAction = FILTER_AND_ACCUM;
}
}
//Run accum only.
@@ -283,7 +282,7 @@ size_t RendererBase::PixelSize() const { return NumChannels() * BytesP
size_t RendererBase::GutterWidth() const { return m_GutterWidth; }
size_t RendererBase::DensityFilterOffset() const { return m_DensityFilterOffset; }
size_t RendererBase::TotalIterCount(size_t strips) const { return (size_t)((size_t)Round(ScaledQuality()) * FinalRasW() * FinalRasH() * strips); }//Use Round() because there can be some roundoff error when interpolating.
-size_t RendererBase::ItersPerTemporalSample() const { return (size_t)ceil(double(TotalIterCount(1)) / double(Passes() * TemporalSamples())); }//Temporal samples is used with animation, which doesn't support strips, so pass 1.
+size_t RendererBase::ItersPerTemporalSample() const { return (size_t)ceil(double(TotalIterCount(1)) / double(TemporalSamples())); }//Temporal samples is used with animation, which doesn't support strips, so pass 1.
eProcessState RendererBase::ProcessState() const { return m_ProcessState; }
eProcessAction RendererBase::ProcessAction() const { return m_ProcessAction; }
EmberStats RendererBase::Stats() const { return m_Stats; }
diff --git a/Source/Ember/RendererBase.h b/Source/Ember/RendererBase.h
index d83438f..01c390f 100644
--- a/Source/Ember/RendererBase.h
+++ b/Source/Ember/RendererBase.h
@@ -165,7 +165,6 @@ public:
virtual eRendererType RendererType() const;
//Abstract render properties, getters only.
- virtual size_t Passes() const = 0;
virtual size_t TemporalSamples() const = 0;
virtual size_t HistBucketSize() const = 0;
virtual size_t FinalRasW() const = 0;
diff --git a/Source/Ember/SheepTools.h b/Source/Ember/SheepTools.h
index f869474..a7b0ba4 100644
--- a/Source/Ember/SheepTools.h
+++ b/Source/Ember/SheepTools.h
@@ -872,7 +872,6 @@ public:
adjustedEmber.m_FinalRasW = (size_t)(ember.m_FinalRasW * scalar);
adjustedEmber.m_FinalRasH = (size_t)(ember.m_FinalRasH * scalar);
adjustedEmber.m_PixelsPerUnit *= scalar;
- adjustedEmber.m_Passes = 1;
adjustedEmber.m_TemporalSamples = 1;
m_Renderer->SetEmber(adjustedEmber);
@@ -1181,9 +1180,6 @@ public:
if (templ.m_Quality > 0)
ember.m_Quality = templ.m_Quality;
- if (templ.m_Passes > 0)
- ember.m_Passes = templ.m_Passes;
-
if (templ.m_TemporalSamples > 0)
ember.m_TemporalSamples = templ.m_TemporalSamples;
@@ -1209,9 +1205,6 @@ public:
if (templ.m_GammaThresh >= 0)
ember.m_GammaThresh = templ.m_GammaThresh;
- if (templ.m_Passes > 0)
- ember.m_Passes = templ.m_Passes;
-
if (templ.m_SpatialFilterType > 0)
ember.m_SpatialFilterType = templ.m_SpatialFilterType;
diff --git a/Source/Ember/TemporalFilter.h b/Source/Ember/TemporalFilter.h
index 693ae71..4931d1c 100644
--- a/Source/Ember/TemporalFilter.h
+++ b/Source/Ember/TemporalFilter.h
@@ -44,14 +44,12 @@ public:
/// Derived class constructors will complete the final part of filter setup.
///
/// Type of the filter.
- /// The number of passes used in the ember being rendered
/// The number of temporal samples in the ember being rendered
/// The width of the filter.
- TemporalFilter(eTemporalFilterType filterType, size_t passes, size_t temporalSamples, T filterWidth)
+ TemporalFilter(eTemporalFilterType filterType, size_t temporalSamples, T filterWidth)
{
- size_t i, steps = passes * temporalSamples;
+ size_t i, steps = temporalSamples;
- m_Passes = passes;
m_TemporalSamples = temporalSamples;
m_FilterWidth = filterWidth;
m_Deltas.resize(steps);
@@ -98,7 +96,6 @@ public:
{
if (this != &filter)
{
- m_Passes = filter.m_Passes;
m_TemporalSamples = filter.m_TemporalSamples;
m_FilterWidth = filter.m_FilterWidth;
m_FilterExp = filter.m_FilterExp;
@@ -146,7 +143,6 @@ public:
/// Accessors.
///
size_t Size() const { return m_Filter.size(); }
- size_t Passes() const { return m_Passes; }
size_t TemporalSamples() const { return m_TemporalSamples; }
T FilterWidth() const { return m_FilterWidth; }
T FilterExp() const { return m_FilterExp; }
@@ -176,7 +172,6 @@ protected:
T m_SumFilt;//The sum of all filter values.
T m_FilterWidth;
T m_FilterExp;
- size_t m_Passes;
size_t m_TemporalSamples;
vector m_Deltas;//Delta vector.
vector m_Filter;//Filter vector.
@@ -194,12 +189,11 @@ public:
///
/// Constructor to create an Exp filter.
///
- /// The number of passes used in the ember being rendered
/// The number of temporal samples in the ember being rendered
/// The width of the filter.
/// The filter exp.
- ExpTemporalFilter(size_t passes, size_t temporalSamples, T filterWidth, T filterExp)
- : TemporalFilter(BOX_TEMPORAL_FILTER, passes, temporalSamples, filterWidth)
+ ExpTemporalFilter(size_t temporalSamples, T filterWidth, T filterExp)
+ : TemporalFilter(BOX_TEMPORAL_FILTER, temporalSamples, filterWidth)
{
if (Size() > 1)
{
@@ -237,11 +231,10 @@ public:
///
/// Constructor to create a Gaussian filter.
///
- /// The number of passes used in the ember being rendered
/// The number of temporal samples in the ember being rendered
/// The width of the filter.
- GaussianTemporalFilter(size_t passes, size_t temporalSamples, T filterWidth)
- : TemporalFilter(GAUSSIAN_TEMPORAL_FILTER, passes, temporalSamples, filterWidth)
+ GaussianTemporalFilter(size_t temporalSamples, T filterWidth)
+ : TemporalFilter(GAUSSIAN_TEMPORAL_FILTER, temporalSamples, filterWidth)
{
if (Size() > 1)
{
@@ -273,11 +266,10 @@ public:
///
/// Constructor to create a Box filter.
///
- /// The number of passes used in the ember being rendered
/// The number of temporal samples in the ember being rendered
/// The width of the filter.
- BoxTemporalFilter(size_t passes, size_t temporalSamples, T filterWidth)
- : TemporalFilter(BOX_TEMPORAL_FILTER, passes, temporalSamples, filterWidth)
+ BoxTemporalFilter(size_t temporalSamples, T filterWidth)
+ : TemporalFilter(BOX_TEMPORAL_FILTER, temporalSamples, filterWidth)
{
if (Size() > 1)
{
@@ -300,23 +292,22 @@ public:
/// Creates the specified filter type based on the filterType enum parameter.
///
/// Type of the filter
- /// The number of passes used in the ember being rendered
/// The number of temporal samples in the ember being rendered
/// The width of the filter
/// The filter exp, only used with Exp filter, otherwise ignored.
/// A pointer to the newly created filter object
- static TemporalFilter* Create(eTemporalFilterType filterType, size_t passes, size_t temporalSamples, T filterWidth, T filterExp = 1)
+ static TemporalFilter* Create(eTemporalFilterType filterType, size_t temporalSamples, T filterWidth, T filterExp = 1)
{
TemporalFilter* filter = nullptr;
if (filterType == BOX_TEMPORAL_FILTER)
- filter = new BoxTemporalFilter(passes, temporalSamples, filterWidth);
+ filter = new BoxTemporalFilter(temporalSamples, filterWidth);
else if (filterType == GAUSSIAN_TEMPORAL_FILTER)
- filter = new GaussianTemporalFilter(passes, temporalSamples, filterWidth);
+ filter = new GaussianTemporalFilter(temporalSamples, filterWidth);
else if (filterType == EXP_TEMPORAL_FILTER)
- filter = new ExpTemporalFilter(passes, temporalSamples, filterWidth, filterExp);
+ filter = new ExpTemporalFilter(temporalSamples, filterWidth, filterExp);
else
- filter = new BoxTemporalFilter(passes, temporalSamples, filterWidth);//Default to box if bad enum passed in.
+ filter = new BoxTemporalFilter(temporalSamples, filterWidth);//Default to box if bad enum passed in.
return filter;
}
diff --git a/Source/Ember/Xform.h b/Source/Ember/Xform.h
index 1a3e34c..a044a21 100644
--- a/Source/Ember/Xform.h
+++ b/Source/Ember/Xform.h
@@ -584,8 +584,6 @@ public:
outPoint->m_VizAdjusted = m_VizAdjusted;
iterHelper.m_Color.x = outPoint->m_ColorX = m_ColorSpeedCache + (m_OneMinusColorCache * inPoint->m_ColorX);
- //This modification returns the affine transformed points if no variations are present.
- //Note this differs from flam3, which would just return zero in that scenario.
if (m_HasPreOrRegularVars)
{
//Compute the pre affine portion of the transform.
@@ -637,6 +635,8 @@ public:
outPoint->m_Z = iterHelper.m_TransZ;
}
}
+ //Return the affine transformed points if no variations are present.
+ //Note this differs from flam3, which would just return zero in that scenario.
else
{
//There are no variations, so the affine transformed points can be assigned directly to the output points.
diff --git a/Source/EmberAnimate/EmberAnimate.rc b/Source/EmberAnimate/EmberAnimate.rc
index 8dcb8de..09e4dc1 100644
--- a/Source/EmberAnimate/EmberAnimate.rc
+++ b/Source/EmberAnimate/EmberAnimate.rc
@@ -49,8 +49,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,4,1,3
- PRODUCTVERSION 0,4,1,3
+ FILEVERSION 0,4,1,4
+ PRODUCTVERSION 0,4,1,4
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -67,12 +67,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as animations with motion blur"
- VALUE "FileVersion", "0.4.1.3"
+ VALUE "FileVersion", "0.4.1.4"
VALUE "InternalName", "EmberAnimate.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberAnimate.rc"
VALUE "ProductName", "Ember Animate"
- VALUE "ProductVersion", "0.4.1.3"
+ VALUE "ProductVersion", "0.4.1.4"
END
END
BLOCK "VarFileInfo"
diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp
index 0fab12d..eebb711 100644
--- a/Source/EmberCL/RendererCL.cpp
+++ b/Source/EmberCL/RendererCL.cpp
@@ -601,11 +601,10 @@ eRenderStatus RendererCL::AccumulatorToFinalImage(unsigned char* pixels, size
/// needed, run on the CPU.
///
/// The number of iterations to run
-/// The pass this is running for
/// The temporal sample within the current pass this is running for
/// Rendering statistics
template
-EmberStats RendererCL::Iterate(size_t iterCount, size_t pass, size_t temporalSample)
+EmberStats RendererCL::Iterate(size_t iterCount, size_t temporalSample)
{
bool b = true;
EmberStats stats;//Do not record bad vals with with GPU. If the user needs to investigate bad vals, use the CPU.
@@ -636,7 +635,7 @@ EmberStats RendererCL::Iterate(size_t iterCount, size_t pass, size_t temporal
if (m_Stats.m_Iters == 0)//Only reset the call count on the beginning of a new render. Do not reset on KEEP_ITERATING.
m_Calls = 0;
- b = RunIter(iterCount, pass, temporalSample, stats.m_Iters);
+ b = RunIter(iterCount, temporalSample, stats.m_Iters);
if (!b || stats.m_Iters == 0)//If no iters were executed, something went catastrophically wrong.
m_Abort = true;
@@ -695,12 +694,11 @@ bool RendererCL::BuildIterProgramForEmber(bool doAccum)
/// between quality of the final image and performance.
///
/// The number of iterations to run
-/// The pass this is running for
-/// The temporal sample within the current pass this is running for
+/// The temporal sample this is running for
/// The storage for the number of iterations ran
/// True if success, else false.
template
-bool RendererCL::RunIter(size_t iterCount, size_t pass, size_t temporalSample, size_t& itersRan)
+bool RendererCL::RunIter(size_t iterCount, size_t temporalSample, size_t& itersRan)
{
Timing t;//, t2(4);
bool b = true;
@@ -795,13 +793,10 @@ bool RendererCL::RunIter(size_t iterCount, size_t pass, size_t temporalSample
(
double
(
- double
- (
- double(m_LastIter + itersRan) / double(ItersPerTemporalSample())
- ) + temporalSample
- ) / (double)TemporalSamples()
- ) + (double)pass
- ) / (double)Passes();
+ double(m_LastIter + itersRan) / double(ItersPerTemporalSample())
+ ) + temporalSample
+ ) / (double)TemporalSamples()
+ );
double percentDiff = percent - m_LastIterPercent;
double toc = m_ProgressTimer.Toc();
@@ -838,15 +833,10 @@ eRenderStatus RendererCL::RunLogScaleFilter()
{
//Timing t(4);
bool b = true;
- int kernelIndex;
+ int kernelIndex = m_Wrapper.FindKernelIndex(m_DEOpenCLKernelCreator.LogScaleAssignDEEntryPoint());
const char* loc = __FUNCTION__;
eRenderStatus status = RENDER_OK;
- if (Passes() == 1)
- kernelIndex = m_Wrapper.FindKernelIndex(m_DEOpenCLKernelCreator.LogScaleAssignDEEntryPoint());
- else
- kernelIndex = m_Wrapper.FindKernelIndex(m_DEOpenCLKernelCreator.LogScaleSumDEEntryPoint());
-
if (kernelIndex != -1)
{
m_DensityFilterCL = ConvertDensityFilter();
diff --git a/Source/EmberCL/RendererCL.h b/Source/EmberCL/RendererCL.h
index 2829765..1ef9760 100644
--- a/Source/EmberCL/RendererCL.h
+++ b/Source/EmberCL/RendererCL.h
@@ -88,12 +88,12 @@ protected:
virtual eRenderStatus LogScaleDensityFilter() override;
virtual eRenderStatus GaussianDensityFilter() override;
virtual eRenderStatus AccumulatorToFinalImage(unsigned char* pixels, size_t finalOffset) override;
- virtual EmberStats Iterate(size_t iterCount, size_t pass, size_t temporalSample) override;
+ virtual EmberStats Iterate(size_t iterCount, size_t temporalSample) override;
private:
//Private functions for making and running OpenCL programs.
bool BuildIterProgramForEmber(bool doAccum = true);
- bool RunIter(size_t iterCount, size_t pass, size_t temporalSample, size_t& itersRan);
+ bool RunIter(size_t iterCount, size_t temporalSample, size_t& itersRan);
eRenderStatus RunLogScaleFilter();
eRenderStatus RunDensityFilter();
eRenderStatus RunFinalAccum();
diff --git a/Source/EmberGenome/EmberGenome.cpp b/Source/EmberGenome/EmberGenome.cpp
index 92860d1..2d76ef3 100644
--- a/Source/EmberGenome/EmberGenome.cpp
+++ b/Source/EmberGenome/EmberGenome.cpp
@@ -27,7 +27,6 @@ void SetDefaultTestValues(Ember& ember)
ember.m_SpatialFilterType = GAUSSIAN_SPATIAL_FILTER;
ember.m_Zoom = 0;
ember.m_Quality = 1;
- ember.m_Passes = 1;
ember.m_TemporalSamples = 1;
ember.m_MaxRadDE = 0;
ember.m_MinRadDE = 0;
diff --git a/Source/EmberGenome/EmberGenome.rc b/Source/EmberGenome/EmberGenome.rc
index b14d08d..6e8d76d 100644
--- a/Source/EmberGenome/EmberGenome.rc
+++ b/Source/EmberGenome/EmberGenome.rc
@@ -49,8 +49,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,4,1,3
- PRODUCTVERSION 0,4,1,3
+ FILEVERSION 0,4,1,4
+ PRODUCTVERSION 0,4,1,4
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -67,12 +67,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Manipulates fractal flames parameter files"
- VALUE "FileVersion", "0.4.1.3"
+ VALUE "FileVersion", "0.4.1.4"
VALUE "InternalName", "EmberGenome.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberGenome.rc"
VALUE "ProductName", "Ember Genome"
- VALUE "ProductVersion", "0.4.1.3"
+ VALUE "ProductVersion", "0.4.1.4"
END
END
BLOCK "VarFileInfo"
diff --git a/Source/EmberRender/EmberRender.rc b/Source/EmberRender/EmberRender.rc
index 41b75a6..786c4b5 100644
--- a/Source/EmberRender/EmberRender.rc
+++ b/Source/EmberRender/EmberRender.rc
@@ -49,8 +49,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,4,1,3
- PRODUCTVERSION 0,4,1,3
+ FILEVERSION 0,4,1,4
+ PRODUCTVERSION 0,4,1,4
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -67,12 +67,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Open Source"
VALUE "FileDescription", "Renders fractal flames as single images"
- VALUE "FileVersion", "0.4.1.3"
+ VALUE "FileVersion", "0.4.1.4"
VALUE "InternalName", "EmberRender.rc"
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
VALUE "OriginalFilename", "EmberRender.rc"
VALUE "ProductName", "Ember Render"
- VALUE "ProductVersion", "0.4.1.3"
+ VALUE "ProductVersion", "0.4.1.4"
END
END
BLOCK "VarFileInfo"
diff --git a/Source/Fractorium/AboutDialog.ui b/Source/Fractorium/AboutDialog.ui
index 0ec6449..9202d7c 100644
--- a/Source/Fractorium/AboutDialog.ui
+++ b/Source/Fractorium/AboutDialog.ui
@@ -52,7 +52,7 @@
- <html><head/><body><p align="center"><br/><span style=" font-size:12pt;">Fractorium 0.4.1.3 Beta</span></p><p align="center"><span style=" font-size:10pt;"><br/>A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.</span></p><p align="center"><span style=" font-size:10pt;">Matt Feemster</span></p></body></html>
+ <html><head/><body><p align="center"><br/><span style=" font-size:12pt;">Fractorium 0.4.1.4 Beta</span></p><p align="center"><span style=" font-size:10pt;"><br/>A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.</span></p><p align="center"><span style=" font-size:10pt;">Matt Feemster</span></p></body></html>
Qt::RichText
diff --git a/Source/Fractorium/FinalRenderDialog.ui b/Source/Fractorium/FinalRenderDialog.ui
index 602ec80..fc6484d 100644
--- a/Source/Fractorium/FinalRenderDialog.ui
+++ b/Source/Fractorium/FinalRenderDialog.ui
@@ -356,13 +356,13 @@
0
- 44
+ 46
16777215
- 44
+ 46
@@ -565,13 +565,13 @@
0
- 198
+ 200
16777215
- 198
+ 200
diff --git a/Source/Fractorium/Fractorium.cpp b/Source/Fractorium/Fractorium.cpp
index fd86bdf..dc6c307 100644
--- a/Source/Fractorium/Fractorium.cpp
+++ b/Source/Fractorium/Fractorium.cpp
@@ -573,7 +573,6 @@ void Fractorium::SetTabOrders()
w = SetTabOrder(this, w, m_DEFilterMaxRadiusSpin);
w = SetTabOrder(this, w, m_DECurveSpin);
- w = SetTabOrder(this, w, m_PassesSpin);
w = SetTabOrder(this, w, m_TemporalSamplesSpin);
w = SetTabOrder(this, w, m_QualitySpin);
w = SetTabOrder(this, w, m_SupersampleSpin);
diff --git a/Source/Fractorium/Fractorium.h b/Source/Fractorium/Fractorium.h
index b9a36fd..b3f3e19 100644
--- a/Source/Fractorium/Fractorium.h
+++ b/Source/Fractorium/Fractorium.h
@@ -152,8 +152,7 @@ public slots:
void OnDEFilterMinRadiusWidthChanged(double d);
void OnDEFilterMaxRadiusWidthChanged(double d);
void OnDEFilterCurveWidthChanged(double d);
- void OnPassesChanged(int d);//Iteration.
- void OnTemporalSamplesChanged(int d);
+ void OnTemporalSamplesChanged(int d);//Iteration.
void OnQualityChanged(double d);
void OnSupersampleChanged(int d);
void OnAffineInterpTypeComboCurrentIndexChanged(int index);
@@ -332,8 +331,7 @@ private:
DoubleSpinBox* m_DEFilterMinRadiusSpin;
DoubleSpinBox* m_DEFilterMaxRadiusSpin;
DoubleSpinBox* m_DECurveSpin;
- SpinBox* m_PassesSpin;//Iteration.
- SpinBox* m_TemporalSamplesSpin;
+ SpinBox* m_TemporalSamplesSpin;//Iteration.
DoubleSpinBox* m_QualitySpin;
SpinBox* m_SupersampleSpin;
StealthComboBox* m_AffineInterpTypeCombo;
diff --git a/Source/Fractorium/Fractorium.rc b/Source/Fractorium/Fractorium.rc
index fe3d5b5..d6dabf4 100644
Binary files a/Source/Fractorium/Fractorium.rc and b/Source/Fractorium/Fractorium.rc differ
diff --git a/Source/Fractorium/Fractorium.ui b/Source/Fractorium/Fractorium.ui
index aecbdc9..0108ced 100644
--- a/Source/Fractorium/Fractorium.ui
+++ b/Source/Fractorium/Fractorium.ui
@@ -944,13 +944,13 @@
0
- 140
+ 117
16777215
- 140
+ 117
@@ -1031,11 +1031,6 @@
false
-
-
- Passes
-
-
Temporal Samples
@@ -1073,7 +1068,7 @@
-
- Passes
+ Temporal Samples
-
@@ -1083,7 +1078,7 @@
-
- Temporal Samples
+ Quality
-
@@ -1093,7 +1088,7 @@
-
- Quality
+ Supersample
-
@@ -1103,7 +1098,7 @@
-
- Supersample
+ Affine Interpolation
-
@@ -1112,21 +1107,11 @@
-
-
- Affine Interpolation
-
-
- -
-
- 0
-
-
- -
Interpolation
- -
+
-
0
@@ -2835,8 +2820,8 @@ SpinBox
0
0
- 238
- 747
+ 118
+ 597
diff --git a/Source/Fractorium/FractoriumEmberController.h b/Source/Fractorium/FractoriumEmberController.h
index 003c50c..0fa2e8a 100644
--- a/Source/Fractorium/FractoriumEmberController.h
+++ b/Source/Fractorium/FractoriumEmberController.h
@@ -126,7 +126,6 @@ public:
virtual void DEFilterMinRadiusWidthChanged(double d) { }
virtual void DEFilterMaxRadiusWidthChanged(double d) { }
virtual void DEFilterCurveWidthChanged(double d) { }
- virtual void PassesChanged(int i) { }
virtual void TemporalSamplesChanged(int d) { }
virtual void QualityChanged(double d) { }
virtual void SupersampleChanged(int d) { }
@@ -341,7 +340,6 @@ public:
virtual void DEFilterMinRadiusWidthChanged(double d) override;
virtual void DEFilterMaxRadiusWidthChanged(double d) override;
virtual void DEFilterCurveWidthChanged(double d) override;
- virtual void PassesChanged(int d) override;
virtual void TemporalSamplesChanged(int d) override;
virtual void QualityChanged(double d) override;
virtual void SupersampleChanged(int d) override;
diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp
index 8201fc0..b1266dc 100644
--- a/Source/Fractorium/FractoriumParams.cpp
+++ b/Source/Fractorium/FractoriumParams.cpp
@@ -85,7 +85,6 @@ void Fractorium::InitParamsUI()
//Iteration.
row = 0;
table = ui.IterationTable;
- SetupSpinner (table, this, row, 1, m_PassesSpin, spinHeight, 1, 3, 1, SIGNAL(valueChanged(int)), SLOT(OnPassesChanged(int)), true, 1, 1, 1);
SetupSpinner (table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 50, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000);
SetupSpinner(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, 10, 10, 10);
SetupSpinner (table, this, row, 1, m_SupersampleSpin, spinHeight, 1, 4, 1, SIGNAL(valueChanged(int)), SLOT(OnSupersampleChanged(int)), true, 1, 1, 1);
@@ -389,16 +388,6 @@ void Fractorium::OnDEFilterCurveWidthChanged(double d) { m_Controller->DEFilterC
/// Iteration.
///
-///
-/// Set the number of passes.
-/// This is a feature that is mostly useless and unused, and may even be removed soon.
-/// It should never be set to a value greater than 1.
-/// Resets the rendering process.
-///
-/// The passes value
-template void FractoriumEmberController::PassesChanged(int i) { Update([&] { m_Ember.m_Passes = i; }); }
-void Fractorium::OnPassesChanged(int d) { m_Controller->PassesChanged(d); }
-
///
/// Set the temporal samples to be used with animation.
/// Called when the temporal samples spinner is changed.
@@ -534,8 +523,7 @@ void FractoriumEmberController::FillParamTablesAndPalette()
m_Fractorium->m_DEFilterMinRadiusSpin->SetValueStealth(m_Ember.m_MinRadDE);
m_Fractorium->m_DEFilterMaxRadiusSpin->SetValueStealth(m_Ember.m_MaxRadDE);
m_Fractorium->m_DECurveSpin->SetValueStealth(m_Ember.m_CurveDE);
- m_Fractorium->m_PassesSpin->SetValueStealth(m_Ember.m_Passes);//Iteration.
- m_Fractorium->m_TemporalSamplesSpin->SetValueStealth(m_Ember.m_TemporalSamples);
+ m_Fractorium->m_TemporalSamplesSpin->SetValueStealth(m_Ember.m_TemporalSamples);//Iteration.
m_Fractorium->m_QualitySpin->SetValueStealth(m_Ember.m_Quality);
m_Fractorium->m_SupersampleSpin->SetValueStealth(m_Ember.m_Supersample);
m_Fractorium->m_AffineInterpTypeCombo->SetCurrentIndexStealth(m_Ember.m_AffineInterp);
@@ -597,7 +585,6 @@ void FractoriumEmberController::ParamsToEmber(Ember& ember)
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_Passes = m_Fractorium->m_PassesSpin->value();
ember.m_TemporalSamples = m_Fractorium->m_TemporalSamplesSpin->value();
ember.m_Quality = m_Fractorium->m_QualitySpin->value();
ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();
diff --git a/Source/Fractorium/FractoriumXforms.cpp b/Source/Fractorium/FractoriumXforms.cpp
index 5c43ec6..cef5f08 100644
--- a/Source/Fractorium/FractoriumXforms.cpp
+++ b/Source/Fractorium/FractoriumXforms.cpp
@@ -305,7 +305,7 @@ void FractoriumEmberController::SetNormalizedWeightText(Xform* xform)
m_Ember.CalcNormalizedWeights(m_NormalizedWeights);
if (index != -1 && index < m_NormalizedWeights.size())
- m_Fractorium->m_XformWeightSpin->setSuffix(QString(" (") + QString::number((double)m_NormalizedWeights[index], 'g', 3) + ")");
+ m_Fractorium->m_XformWeightSpin->setSuffix(QString(" (") + QLocale::system().toString((double)m_NormalizedWeights[index], 'g', 3) + ")");
}
}
diff --git a/Source/Fractorium/OptionsDialog.ui b/Source/Fractorium/OptionsDialog.ui
index 3e267a5..cec1cc8 100644
--- a/Source/Fractorium/OptionsDialog.ui
+++ b/Source/Fractorium/OptionsDialog.ui
@@ -324,13 +324,13 @@ in interactive mode for each mouse movement
0
- 66
+ 68
16777215
- 66
+ 68
@@ -507,13 +507,13 @@ in interactive mode for each mouse movement
120
- 66
+ 68
16777215
- 66
+ 68