mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-01-21 05:00:06 -05:00
Remove passes.
Fix some table dimensions. Proper locale for normalized weight.
This commit is contained in:
parent
6b2b6ede7f
commit
b2600f0fff
@ -6,7 +6,7 @@
|
||||
<ProductVersion>3.7</ProductVersion>
|
||||
<ProjectGuid>{c8096c47-e358-438c-a520-146d46b0637d}</ProjectGuid>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<OutputName>Fractorium_Beta_0.4.1.3</OutputName>
|
||||
<OutputName>Fractorium_Beta_0.4.1.4</OutputName>
|
||||
<OutputType>Package</OutputType>
|
||||
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
||||
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<?define ProductVersion="0.4.1.3" ?>
|
||||
<?define ProductVersion="0.4.1.4" ?>
|
||||
<?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?>
|
||||
<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?>
|
||||
<?define Manufacturer="Fractorium"?>
|
||||
|
@ -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<T>::m_CamDepthBlur>(embers, coefs, size);
|
||||
InterpX<m3T, &Ember<T>::m_CamMat>(embers, coefs, size);
|
||||
InterpT<&Ember<T>::m_Rotate>(embers, coefs, size);
|
||||
InterpI<&Ember<T>::m_Passes>(embers, coefs, size);
|
||||
InterpI<&Ember<T>::m_TemporalSamples>(embers, coefs, size);
|
||||
InterpT<&Ember<T>::m_MaxRadDE>(embers, coefs, size);
|
||||
InterpT<&Ember<T>::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.
|
||||
|
@ -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<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way.
|
||||
#define ISAAC_SIZE 4
|
||||
|
@ -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 << "\"";
|
||||
|
@ -265,14 +265,13 @@ bool Renderer<T, bucketT>::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<TemporalFilter<T>>(
|
||||
TemporalFilterCreator<T>::Create(m_Ember.m_TemporalFilterType, m_Ember.m_Passes, m_Ember.m_TemporalSamples, m_Ember.m_TemporalFilterWidth, m_Ember.m_TemporalFilterExp));
|
||||
TemporalFilterCreator<T>::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<T, bucketT>::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<T, bucketT>::Run(vector<unsigned char>& 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<T, bucketT>::Run(vector<unsigned char>& 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<T, bucketT>::Run(vector<unsigned char>& 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<T, bucketT>::Run(vector<unsigned char>& 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<T, bucketT>::Run(vector<unsigned char>& 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<T>::Interpolate(m_Embers, deTime, 0, m_Ember);
|
||||
//it.Toc("Interp 2");
|
||||
|
||||
ClampGte<T>(m_Ember.m_MinRadDE, 0);
|
||||
ClampGte<T>(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<T>::Interpolate(m_Embers, deTime, 0, m_Ember);
|
||||
//it.Toc("Interp 2");
|
||||
Interpolater<T>::Interpolate(m_Embers, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
|
||||
|
||||
ClampGte<T>(m_Ember.m_MinRadDE, 0);
|
||||
ClampGte<T>(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<T>::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<T, bucketT>::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<T, bucketT>::AccumulatorToFinalImage(unsigned char* pixel
|
||||
/// which by default is 10,000 iterations.
|
||||
/// </summary>
|
||||
/// <param name="iterCount">The number of iterations to run</param>
|
||||
/// <param name="pass">The pass this is running for</param>
|
||||
/// <param name="temporalSample">The temporal sample within the current pass this is running for</param>
|
||||
/// <param name="temporalSample">The temporal sample this is running for</param>
|
||||
/// <returns>Rendering statistics</returns>
|
||||
template <typename T, typename bucketT>
|
||||
EmberStats Renderer<T, bucketT>::Iterate(size_t iterCount, size_t pass, size_t temporalSample)
|
||||
EmberStats Renderer<T, bucketT>::Iterate(size_t iterCount, size_t temporalSample)
|
||||
{
|
||||
//Timing t2(4);
|
||||
m_IterTimer.Tic();
|
||||
@ -1245,7 +1185,7 @@ EmberStats Renderer<T, bucketT>::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<T, bucketT>::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<T, bucketT>::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 <typename T, typename bucketT> ePaletteMode Renderer<T, bucketT>::
|
||||
/// Virtual ember wrappers overridden from RendererBase, getters only.
|
||||
/// </summary>
|
||||
|
||||
template <typename T, typename bucketT> size_t Renderer<T, bucketT>::Passes() const { return m_Ember.m_Passes; }
|
||||
template <typename T, typename bucketT> size_t Renderer<T, bucketT>::TemporalSamples() const { return m_Ember.m_TemporalSamples; }
|
||||
template <typename T, typename bucketT> size_t Renderer<T, bucketT>::FinalRasW() const { return m_Ember.m_FinalRasW; }
|
||||
template <typename T, typename bucketT> size_t Renderer<T, bucketT>::FinalRasH() const { return m_Ember.m_FinalRasH; }
|
||||
|
@ -74,7 +74,7 @@ protected:
|
||||
virtual eRenderStatus GaussianDensityFilter();
|
||||
virtual eRenderStatus AccumulatorToFinalImage(vector<unsigned char>& 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;
|
||||
|
@ -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<void(void)> 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<void(void)> 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; }
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -44,14 +44,12 @@ public:
|
||||
/// Derived class constructors will complete the final part of filter setup.
|
||||
/// </summary>
|
||||
/// <param name="filterType">Type of the filter.</param>
|
||||
/// <param name="passes">The number of passes used in the ember being rendered</param>
|
||||
/// <param name="temporalSamples">The number of temporal samples in the ember being rendered</param>
|
||||
/// <param name="filterWidth">The width of the filter.</param>
|
||||
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.
|
||||
/// </summary>
|
||||
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<T> m_Deltas;//Delta vector.
|
||||
vector<T> m_Filter;//Filter vector.
|
||||
@ -194,12 +189,11 @@ public:
|
||||
/// <summary>
|
||||
/// Constructor to create an Exp filter.
|
||||
/// </summary>
|
||||
/// <param name="passes">The number of passes used in the ember being rendered</param>
|
||||
/// <param name="temporalSamples">The number of temporal samples in the ember being rendered</param>
|
||||
/// <param name="filterWidth">The width of the filter.</param>
|
||||
/// <param name="filterExp">The filter exp.</param>
|
||||
ExpTemporalFilter(size_t passes, size_t temporalSamples, T filterWidth, T filterExp)
|
||||
: TemporalFilter<T>(BOX_TEMPORAL_FILTER, passes, temporalSamples, filterWidth)
|
||||
ExpTemporalFilter(size_t temporalSamples, T filterWidth, T filterExp)
|
||||
: TemporalFilter<T>(BOX_TEMPORAL_FILTER, temporalSamples, filterWidth)
|
||||
{
|
||||
if (Size() > 1)
|
||||
{
|
||||
@ -237,11 +231,10 @@ public:
|
||||
/// <summary>
|
||||
/// Constructor to create a Gaussian filter.
|
||||
/// </summary>
|
||||
/// <param name="passes">The number of passes used in the ember being rendered</param>
|
||||
/// <param name="temporalSamples">The number of temporal samples in the ember being rendered</param>
|
||||
/// <param name="filterWidth">The width of the filter.</param>
|
||||
GaussianTemporalFilter(size_t passes, size_t temporalSamples, T filterWidth)
|
||||
: TemporalFilter<T>(GAUSSIAN_TEMPORAL_FILTER, passes, temporalSamples, filterWidth)
|
||||
GaussianTemporalFilter(size_t temporalSamples, T filterWidth)
|
||||
: TemporalFilter<T>(GAUSSIAN_TEMPORAL_FILTER, temporalSamples, filterWidth)
|
||||
{
|
||||
if (Size() > 1)
|
||||
{
|
||||
@ -273,11 +266,10 @@ public:
|
||||
/// <summary>
|
||||
/// Constructor to create a Box filter.
|
||||
/// </summary>
|
||||
/// <param name="passes">The number of passes used in the ember being rendered</param>
|
||||
/// <param name="temporalSamples">The number of temporal samples in the ember being rendered</param>
|
||||
/// <param name="filterWidth">The width of the filter.</param>
|
||||
BoxTemporalFilter(size_t passes, size_t temporalSamples, T filterWidth)
|
||||
: TemporalFilter<T>(BOX_TEMPORAL_FILTER, passes, temporalSamples, filterWidth)
|
||||
BoxTemporalFilter(size_t temporalSamples, T filterWidth)
|
||||
: TemporalFilter<T>(BOX_TEMPORAL_FILTER, temporalSamples, filterWidth)
|
||||
{
|
||||
if (Size() > 1)
|
||||
{
|
||||
@ -300,23 +292,22 @@ public:
|
||||
/// Creates the specified filter type based on the filterType enum parameter.
|
||||
/// </summary>
|
||||
/// <param name="filterType">Type of the filter</param>
|
||||
/// <param name="passes">The number of passes used in the ember being rendered</param>
|
||||
/// <param name="temporalSamples">The number of temporal samples in the ember being rendered</param>
|
||||
/// <param name="filterWidth">The width of the filter</param>
|
||||
/// <param name="filterExp">The filter exp, only used with Exp filter, otherwise ignored.</param>
|
||||
/// <returns>A pointer to the newly created filter object</returns>
|
||||
static TemporalFilter<T>* Create(eTemporalFilterType filterType, size_t passes, size_t temporalSamples, T filterWidth, T filterExp = 1)
|
||||
static TemporalFilter<T>* Create(eTemporalFilterType filterType, size_t temporalSamples, T filterWidth, T filterExp = 1)
|
||||
{
|
||||
TemporalFilter<T>* filter = nullptr;
|
||||
|
||||
if (filterType == BOX_TEMPORAL_FILTER)
|
||||
filter = new BoxTemporalFilter<T>(passes, temporalSamples, filterWidth);
|
||||
filter = new BoxTemporalFilter<T>(temporalSamples, filterWidth);
|
||||
else if (filterType == GAUSSIAN_TEMPORAL_FILTER)
|
||||
filter = new GaussianTemporalFilter<T>(passes, temporalSamples, filterWidth);
|
||||
filter = new GaussianTemporalFilter<T>(temporalSamples, filterWidth);
|
||||
else if (filterType == EXP_TEMPORAL_FILTER)
|
||||
filter = new ExpTemporalFilter<T>(passes, temporalSamples, filterWidth, filterExp);
|
||||
filter = new ExpTemporalFilter<T>(temporalSamples, filterWidth, filterExp);
|
||||
else
|
||||
filter = new BoxTemporalFilter<T>(passes, temporalSamples, filterWidth);//Default to box if bad enum passed in.
|
||||
filter = new BoxTemporalFilter<T>(temporalSamples, filterWidth);//Default to box if bad enum passed in.
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -601,11 +601,10 @@ eRenderStatus RendererCL<T>::AccumulatorToFinalImage(unsigned char* pixels, size
|
||||
/// needed, run on the CPU.
|
||||
/// </summary>
|
||||
/// <param name="iterCount">The number of iterations to run</param>
|
||||
/// <param name="pass">The pass this is running for</param>
|
||||
/// <param name="temporalSample">The temporal sample within the current pass this is running for</param>
|
||||
/// <returns>Rendering statistics</returns>
|
||||
template <typename T>
|
||||
EmberStats RendererCL<T>::Iterate(size_t iterCount, size_t pass, size_t temporalSample)
|
||||
EmberStats RendererCL<T>::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<T>::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<T>::BuildIterProgramForEmber(bool doAccum)
|
||||
/// between quality of the final image and performance.
|
||||
/// </summary>
|
||||
/// <param name="iterCount">The number of iterations to run</param>
|
||||
/// <param name="pass">The pass this is running for</param>
|
||||
/// <param name="temporalSample">The temporal sample within the current pass this is running for</param>
|
||||
/// <param name="temporalSample">The temporal sample this is running for</param>
|
||||
/// <param name="itersRan">The storage for the number of iterations ran</param>
|
||||
/// <returns>True if success, else false.</returns>
|
||||
template <typename T>
|
||||
bool RendererCL<T>::RunIter(size_t iterCount, size_t pass, size_t temporalSample, size_t& itersRan)
|
||||
bool RendererCL<T>::RunIter(size_t iterCount, size_t temporalSample, size_t& itersRan)
|
||||
{
|
||||
Timing t;//, t2(4);
|
||||
bool b = true;
|
||||
@ -795,13 +793,10 @@ bool RendererCL<T>::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<T>::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();
|
||||
|
@ -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();
|
||||
|
@ -27,7 +27,6 @@ void SetDefaultTestValues(Ember<T>& 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;
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -52,7 +52,7 @@
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><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></string>
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
|
@ -356,13 +356,13 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>44</height>
|
||||
<height>46</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>44</height>
|
||||
<height>46</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
@ -565,13 +565,13 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>198</height>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>198</height>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Binary file not shown.
@ -944,13 +944,13 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>140</height>
|
||||
<height>117</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>140</height>
|
||||
<height>117</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
@ -1031,11 +1031,6 @@
|
||||
<attribute name="verticalHeaderStretchLastSection">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>Passes</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>Temporal Samples</string>
|
||||
@ -1073,7 +1068,7 @@
|
||||
</column>
|
||||
<item row="0" column="0">
|
||||
<property name="text">
|
||||
<string>Passes</string>
|
||||
<string>Temporal Samples</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
@ -1083,7 +1078,7 @@
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<property name="text">
|
||||
<string>Temporal Samples</string>
|
||||
<string>Quality</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
@ -1093,7 +1088,7 @@
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<property name="text">
|
||||
<string>Quality</string>
|
||||
<string>Supersample</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
@ -1103,7 +1098,7 @@
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<property name="text">
|
||||
<string>Supersample</string>
|
||||
<string>Affine Interpolation</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
@ -1112,21 +1107,11 @@
|
||||
</property>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<property name="text">
|
||||
<string>Affine Interpolation</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<property name="text">
|
||||
<string>Interpolation</string>
|
||||
</property>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="1">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
@ -2835,8 +2820,8 @@ SpinBox
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>238</width>
|
||||
<height>747</height>
|
||||
<width>118</width>
|
||||
<height>597</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="palette">
|
||||
|
@ -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;
|
||||
|
@ -85,7 +85,6 @@ void Fractorium::InitParamsUI()
|
||||
//Iteration.
|
||||
row = 0;
|
||||
table = ui.IterationTable;
|
||||
SetupSpinner<SpinBox, int> (table, this, row, 1, m_PassesSpin, spinHeight, 1, 3, 1, SIGNAL(valueChanged(int)), SLOT(OnPassesChanged(int)), true, 1, 1, 1);
|
||||
SetupSpinner<SpinBox, int> (table, this, row, 1, m_TemporalSamplesSpin, spinHeight, 1, 5000, 50, SIGNAL(valueChanged(int)), SLOT(OnTemporalSamplesChanged(int)), true, 1000);
|
||||
SetupSpinner<DoubleSpinBox, double>(table, this, row, 1, m_QualitySpin, spinHeight, 1, dmax, 50, SIGNAL(valueChanged(double)), SLOT(OnQualityChanged(double)), true, 10, 10, 10);
|
||||
SetupSpinner<SpinBox, int> (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.
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="d">The passes value</param>
|
||||
template <typename T> void FractoriumEmberController<T>::PassesChanged(int i) { Update([&] { m_Ember.m_Passes = i; }); }
|
||||
void Fractorium::OnPassesChanged(int d) { m_Controller->PassesChanged(d); }
|
||||
|
||||
/// <summary>
|
||||
/// Set the temporal samples to be used with animation.
|
||||
/// Called when the temporal samples spinner is changed.
|
||||
@ -534,8 +523,7 @@ void FractoriumEmberController<T>::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<T>::ParamsToEmber(Ember<T>& 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();
|
||||
|
@ -305,7 +305,7 @@ void FractoriumEmberController<T>::SetNormalizedWeightText(Xform<T>* 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) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,13 +324,13 @@ in interactive mode for each mouse movement</string>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>66</height>
|
||||
<height>68</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>66</height>
|
||||
<height>68</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
@ -507,13 +507,13 @@ in interactive mode for each mouse movement</string>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>66</height>
|
||||
<height>68</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>66</height>
|
||||
<height>68</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
|
Loading…
Reference in New Issue
Block a user