--User changes

-Remove Hue as a saved parameter, as well as animation parameters associated with it. It's now a GUI-only field that is never saved.
 -Make histogram, density filter buffer, and all associated fields always float, even when using double. In that case, only the iteration calculations are now double. Suggested by Thomas Ludwig.
 -Print all three kernels in EmberRender when the --dump_kernel option is specified.
 -Apply variations filter to randoms.

--Bug fixes
 -Fix bug where hue was not being preserved when switching controllers and embers. Very hard to repro bug, but mostly overcome by eliminating hue as a saved parameter.

--Code changes
 -De-templatized DEOpenCLKernelCreator and FinalAccumOpenCLKernelCreator. They now just take a bool as a parameter to specify double precision.
 -To accommodate the buffers being float, introduce a new #define types in EmberCL called real4_bucket, and real4reals_bucket.
 -Density and spatial filtering structs now use this type.
 -ConvertDensityFilter() and ConvertSpatialFilter() no longer return a value, they just assign to the member.
This commit is contained in:
mfeemster
2015-08-10 20:10:23 -07:00
parent 6b702334b9
commit eecd3c254f
38 changed files with 695 additions and 771 deletions

View File

@ -412,6 +412,6 @@ EXPORT_TWO_TYPE_EMBER(float, float)
#ifdef DO_DOUBLE
EXPORT_SINGLE_TYPE_EMBER(double)
EXPORT_TWO_TYPE_EMBER(double, double)
EXPORT_TWO_TYPE_EMBER(double, float)
#endif
}

View File

@ -121,7 +121,6 @@ public:
m_CenterY = T(ember.m_CenterY);
m_RotCenterY = T(ember.m_RotCenterY);
m_Rotate = T(ember.m_Rotate);
m_Hue = T(ember.m_Hue);
m_Brightness = T(ember.m_Brightness);
m_Gamma = T(ember.m_Gamma);
m_Vibrancy = T(ember.m_Vibrancy);
@ -219,7 +218,6 @@ public:
m_CenterY = 0;
m_RotCenterY = 0;
m_Rotate = 0;
m_Hue = 0;
m_Brightness = 4;
m_Gamma = 4;
m_Vibrancy = 1;
@ -793,7 +791,6 @@ public:
InterpT<&Ember<T>::m_CenterY>(embers, coefs, size);
InterpT<&Ember<T>::m_RotCenterY>(embers, coefs, size);
InterpT<&Ember<T>::m_Rotate>(embers, coefs, size);
InterpT<&Ember<T>::m_Hue>(embers, coefs, size);
InterpT<&Ember<T>::m_Brightness>(embers, coefs, size);
InterpT<&Ember<T>::m_Gamma>(embers, coefs, size);
InterpT<&Ember<T>::m_Vibrancy>(embers, coefs, size);
@ -1335,9 +1332,6 @@ public:
case FLAME_MOTION_ROTATE:
APP_FMP(m_Rotate);
break;
case FLAME_MOTION_HUE:
APP_FMP(m_Hue);
break;
case FLAME_MOTION_BRIGHTNESS:
APP_FMP(m_Brightness);
break;
@ -1381,7 +1375,6 @@ public:
m_Vibrancy = 1;
m_Brightness = 4;
m_Symmetry = 0;
m_Hue = 0;
m_Rotate = 0;
m_PixelsPerUnit = 50;
m_Interp = EMBER_INTERP_LINEAR;
@ -1502,7 +1495,6 @@ public:
<< "CenterY: " << m_CenterY << endl
<< "RotCenterY: " << m_RotCenterY << endl
<< "Rotate: " << m_Rotate << endl
<< "Hue: " << m_Hue << endl
<< "Brightness: " << m_Brightness << endl
<< "Gamma: " << m_Gamma << endl
<< "Vibrancy: " << m_Vibrancy << endl
@ -1646,11 +1638,6 @@ public:
//Xml field: "rotate".
T m_Rotate;
//When specifying the palette as an index in the palette file, rather than inserted in the Xml, it can optionally have its hue
//rotated by this amount.
//Xml field: "hue".
T m_Hue;
//Determine how bright to make the image during final accumulation.
//Xml field: "brightness".
T m_Brightness;

View File

@ -96,6 +96,7 @@ static inline size_t NowMs()
#define v2T glm::tvec2<T, glm::defaultp>
#define v3T glm::tvec3<T, glm::defaultp>
#define v4T glm::tvec4<T, glm::defaultp>
#define v4bT glm::tvec4<bucketT, glm::defaultp>
#define m2T glm::tmat2x2<T, glm::defaultp>
#define m3T glm::tmat3x3<T, glm::defaultp>
#define m4T glm::tmat4x4<T, glm::defaultp>
@ -104,6 +105,7 @@ static inline size_t NowMs()
#define v2T glm::detail::tvec2<T, glm::defaultp>
#define v3T glm::detail::tvec3<T, glm::defaultp>
#define v4T glm::detail::tvec4<T, glm::defaultp>
#define v4bT glm::detail::tvec4<bucketT, glm::defaultp>
#define m2T glm::detail::tmat2x2<T, glm::defaultp>
#define m3T glm::detail::tmat3x3<T, glm::defaultp>
#define m4T glm::detail::tmat4x4<T, glm::defaultp>
@ -132,14 +134,13 @@ enum eEmberMotionParam : uint
FLAME_MOTION_CENTER_X = 7,
FLAME_MOTION_CENTER_Y = 8,
FLAME_MOTION_ROTATE = 9,
FLAME_MOTION_HUE = 10,
FLAME_MOTION_BRIGHTNESS = 11,
FLAME_MOTION_GAMMA = 12,
FLAME_MOTION_GAMMA_THRESH = 13,
FLAME_MOTION_HIGHLIGHT_POWER = 14,
FLAME_MOTION_BACKGROUND_R = 15,
FLAME_MOTION_BACKGROUND_G = 16,
FLAME_MOTION_BACKGROUND_B = 17,
FLAME_MOTION_VIBRANCY = 18
FLAME_MOTION_BRIGHTNESS = 10,
FLAME_MOTION_GAMMA = 11,
FLAME_MOTION_GAMMA_THRESH = 12,
FLAME_MOTION_HIGHLIGHT_POWER = 13,
FLAME_MOTION_BACKGROUND_R = 14,
FLAME_MOTION_BACKGROUND_G = 15,
FLAME_MOTION_BACKGROUND_B = 16,
FLAME_MOTION_VIBRANCY = 17
};
}

View File

@ -792,9 +792,6 @@ private:
case FLAME_MOTION_ROTATE:
os << " rotate=\"" << motion.m_MotionParams[i].second << "\"";
break;
case FLAME_MOTION_HUE:
os << " hue=\"" << motion.m_MotionParams[i].second << "\"";
break;
case FLAME_MOTION_BRIGHTNESS:
os << " brightness=\"" << motion.m_MotionParams[i].second << "\"";
break;

View File

@ -276,7 +276,7 @@ public:
}
Isaac(ctx); //Fill in the first set of results.
ctx->randcnt = N;//TODO//0;//Prepare to use the first set of results.
ctx->randcnt = N;//0;//Prepare to use the first set of results.
}
/// <summary>

View File

@ -212,7 +212,7 @@ bool Renderer<T, bucketT>::CreateDEFilter(bool& newAlloc)
(m_Ember.m_CurveDE != m_DensityFilter->Curve()) ||
(m_Ember.m_Supersample != m_DensityFilter->Supersample()))
{
m_DensityFilter = unique_ptr<DensityFilter<T>>(new DensityFilter<T>(m_Ember.m_MinRadDE, m_Ember.m_MaxRadDE, m_Ember.m_CurveDE, m_Ember.m_Supersample));
m_DensityFilter = unique_ptr<DensityFilter<bucketT>>(new DensityFilter<bucketT>(bucketT(m_Ember.m_MinRadDE), bucketT(m_Ember.m_MaxRadDE), bucketT(m_Ember.m_CurveDE), m_Ember.m_Supersample));
newAlloc = true;
}
@ -251,8 +251,8 @@ bool Renderer<T, bucketT>::CreateSpatialFilter(bool& newAlloc)
(m_Ember.m_Supersample != m_SpatialFilter->Supersample()) ||
(m_PixelAspectRatio != m_SpatialFilter->PixelAspectRatio()))
{
m_SpatialFilter = unique_ptr<SpatialFilter<T>>(
SpatialFilterCreator<T>::Create(m_Ember.m_SpatialFilterType, m_Ember.m_SpatialFilterRadius, m_Ember.m_Supersample, m_PixelAspectRatio));
m_SpatialFilter = unique_ptr<SpatialFilter<bucketT>>(
SpatialFilterCreator<bucketT>::Create(m_Ember.m_SpatialFilterType, bucketT(m_Ember.m_SpatialFilterRadius), m_Ember.m_Supersample, bucketT(m_PixelAspectRatio)));
m_Ember.m_SpatialFilterRadius = m_SpatialFilter->FilterRadius();//It may have been changed internally if it was too small, so ensure they're synced.
newAlloc = true;
@ -386,8 +386,8 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
if ((filterAndAccumOnly || accumOnly) && TemporalSamples() == 1)//Disallow jumping when temporal samples > 1.
{
m_Ember = m_Embers[0];
m_Vibrancy = m_Ember.m_Vibrancy;
m_Gamma = m_Ember.m_Gamma;
m_Vibrancy = Vibrancy();
m_Gamma = Gamma();
m_Background = m_Ember.m_Background;
if (filterAndAccumOnly)
@ -517,11 +517,11 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
//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_Vibrancy += Vibrancy();
m_Gamma += Gamma();
m_Background.r += bucketT(m_Ember.m_Background.r);
m_Background.g += bucketT(m_Ember.m_Background.g);
m_Background.b += bucketT(m_Ember.m_Background.b);
m_VibGamCount++;
m_LastIter = 0;
temporalSample++;
@ -554,7 +554,7 @@ FilterAndAccum:
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;
m_K1 = bucketT((Brightness() * 268) / 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
@ -562,10 +562,10 @@ FilterAndAccum:
if (forceOutput)
{
T quality = (T(m_Stats.m_Iters) / T(FinalDimensions())) * (m_Scale * m_Scale);
m_K2 = (Supersample() * Supersample()) / (area * quality * m_TemporalFilter->SumFilt());
m_K2 = bucketT((Supersample() * Supersample()) / (area * quality * m_TemporalFilter->SumFilt()));
}
else
m_K2 = (Supersample() * Supersample()) / (area * m_ScaledQuality * m_TemporalFilter->SumFilt());
m_K2 = bucketT((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();
@ -824,11 +824,11 @@ eRenderStatus Renderer<T, bucketT>::LogScaleDensityFilter()
//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;
bucketT 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);
m_AccumulatorBuckets[index] = m_HistBuckets[index] * logScale;
}
}
});
@ -850,7 +850,7 @@ eRenderStatus Renderer<T, bucketT>::GaussianDensityFilter()
Timing totalTime, localTime;
bool scf = !(Supersample() & 1);
intmax_t ss = Floor<T>(Supersample() / T(2));
T scfact = pow(Supersample() / (Supersample() + T(1.0)), T(2.0));
T scfact = pow(Supersample() / (Supersample() + T(1)), T(2));
size_t threads = m_ThreadsToUse;
size_t startRow = Supersample() - 1;
@ -874,8 +874,8 @@ eRenderStatus Renderer<T, bucketT>::GaussianDensityFilter()
size_t bucketRowStart = j * m_SuperRasW;//Pull out of inner loop for optimization.
const tvec4<bucketT, glm::defaultp>* bucket;
const tvec4<bucketT, glm::defaultp>* buckets = m_HistBuckets.data();
const T* filterCoefs = m_DensityFilter->Coefs();
const T* filterWidths = m_DensityFilter->Widths();
const bucketT* filterCoefs = m_DensityFilter->Coefs();
const bucketT* filterWidths = m_DensityFilter->Widths();
for (intmax_t i = startCol; i < endCol; i++)
{
@ -888,7 +888,7 @@ eRenderStatus Renderer<T, bucketT>::GaussianDensityFilter()
if (bucket->a == 0)
continue;
T cacheLog = (m_K1 * log(T(1.0) + bucket->a * m_K2)) / bucket->a;//Caching this calculation gives a 30% speedup.
bucketT cacheLog = (m_K1 * log(1 + bucket->a * m_K2)) / bucket->a;//Caching this calculation gives a 30% speedup.
if (ss == 0)
{
@ -938,10 +938,10 @@ eRenderStatus Renderer<T, bucketT>::GaussianDensityFilter()
if (filterCoefs[filterCoefIndex] == 0)
continue;
T logScale = filterCoefs[filterCoefIndex] * cacheLog;
bucketT logScale = filterCoefs[filterCoefIndex] * cacheLog;
//Original first assigned the fields, then scaled them. Combine into a single step for a 1% optimization.
logScaleBucket = (*bucket * bucketT(logScale));
logScaleBucket = (*bucket * logScale);
if (jj == 0 && ii == 0)
{
@ -1036,8 +1036,8 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(byte* pixels, size_t
EnterFinalAccum();
//Timing t(4);
size_t filterWidth = m_SpatialFilter->FinalFilterWidth();
T g, linRange, vibrancy;
Color<T> background;
bucketT g, linRange, vibrancy;
Color<bucketT> background;
pixels += finalOffset;
PrepFinalAccumVals(background, g, linRange, vibrancy);
@ -1090,7 +1090,7 @@ eRenderStatus Renderer<T, bucketT>::AccumulatorToFinalImage(byte* pixels, size_t
for (ii = 0; ii < filterWidth; ii++)
{
//Need to dereference the spatial filter pointer object to use the [] operator. Makes no speed difference.
bucketT k = bucketT((*m_SpatialFilter)[ii + filterKRowIndex]);
bucketT k = ((*m_SpatialFilter)[ii + filterKRowIndex]);
newBucket += (m_AccumulatorBuckets[(x + ii) + accumRowIndex] * k);
}
@ -1340,12 +1340,12 @@ void Renderer<T, bucketT>::PixelAspectRatio(T pixelAspectRatio)
template <typename T, typename bucketT> T Renderer<T, bucketT>::Scale() const { return m_Scale; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::PixelsPerUnitX() const { return m_PixelsPerUnitX; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::PixelsPerUnitY() const { return m_PixelsPerUnitY; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::K1() const { return m_K1; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::K2() const { return m_K2; }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::K1() const { return m_K1; }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::K2() const { return m_K2; }
template <typename T, typename bucketT> const CarToRas<T>* Renderer<T, bucketT>::CoordMap() const { return &m_CarToRas; }
template <typename T, typename bucketT> tvec4<bucketT, glm::defaultp>* Renderer<T, bucketT>::HistBuckets() { return m_HistBuckets.data(); }
template <typename T, typename bucketT> tvec4<bucketT, glm::defaultp>* Renderer<T, bucketT>::AccumulatorBuckets() { return m_AccumulatorBuckets.data(); }
template <typename T, typename bucketT> SpatialFilter<T>* Renderer<T, bucketT>::GetSpatialFilter() { return m_SpatialFilter.get(); }
template <typename T, typename bucketT> SpatialFilter<bucketT>* Renderer<T, bucketT>::GetSpatialFilter() { return m_SpatialFilter.get(); }
template <typename T, typename bucketT> TemporalFilter<T>* Renderer<T, bucketT>::GetTemporalFilter() { return m_TemporalFilter.get(); }
/// <summary>
@ -1374,12 +1374,11 @@ template <typename T, typename bucketT> T Renderer<T, bucketT>::
template <typename T, typename bucketT> T Renderer<T, bucketT>::CenterX() const { return m_Ember.m_CenterX; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::CenterY() const { return m_Ember.m_CenterY; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::Rotate() const { return m_Ember.m_Rotate; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::Hue() const { return m_Ember.m_Hue; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::Brightness() const { return m_Ember.m_Brightness; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::Gamma() const { return m_Ember.m_Gamma; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::Vibrancy() const { return m_Ember.m_Vibrancy; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::GammaThresh() const { return m_Ember.m_GammaThresh; }
template <typename T, typename bucketT> T Renderer<T, bucketT>::HighlightPower() const { return m_Ember.m_HighlightPower; }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::Brightness() const { return bucketT(m_Ember.m_Brightness); }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::Gamma() const { return bucketT(m_Ember.m_Gamma); }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::Vibrancy() const { return bucketT(m_Ember.m_Vibrancy); }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::GammaThresh() const { return bucketT(m_Ember.m_GammaThresh); }
template <typename T, typename bucketT> bucketT Renderer<T, bucketT>::HighlightPower() const { return bucketT(m_Ember.m_HighlightPower); }
template <typename T, typename bucketT> Color<T> Renderer<T, bucketT>::Background() const { return m_Ember.m_Background; }
template <typename T, typename bucketT> const Xform<T>* Renderer<T, bucketT>::Xforms() const { return m_Ember.Xforms(); }
template <typename T, typename bucketT> Xform<T>* Renderer<T, bucketT>::NonConstXforms() { return m_Ember.NonConstXforms(); }
@ -1420,20 +1419,20 @@ template <typename T, typename bucketT> Point<T>* Renderer<T, bucketT>::Sample
/// <param name="linRange">The computed linear range</param>
/// <param name="vibrancy">The computed vibrancy</param>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::PrepFinalAccumVals(Color<T>& background, T& g, T& linRange, T& vibrancy)
void Renderer<T, bucketT>::PrepFinalAccumVals(Color<bucketT>& background, bucketT& g, bucketT& linRange, bucketT& vibrancy)
{
//If they are doing incremental rendering, they can get here without doing a full temporal
//sample, which means the values will be zero.
vibrancy = m_Vibrancy == 0 ? m_Ember.m_Vibrancy : m_Vibrancy;
vibrancy = m_Vibrancy == 0 ? Vibrancy() : m_Vibrancy;
size_t vibGamCount = m_VibGamCount == 0 ? 1 : m_VibGamCount;
T gamma = m_Gamma == 0 ? m_Ember.m_Gamma : m_Gamma;
g = T(1.0) / ClampGte<T>(gamma / vibGamCount, T(0.01));//Ensure a divide by zero doesn't occur.
bucketT gamma = m_Gamma == 0 ? Gamma() : m_Gamma;
g = 1 / ClampGte<bucketT>(gamma / vibGamCount, bucketT(0.01));//Ensure a divide by zero doesn't occur.
linRange = GammaThresh();
vibrancy /= vibGamCount;
background.x = (IsNearZero(m_Background.r) ? m_Ember.m_Background.r : m_Background.r) / (vibGamCount / T(256.0));//Background is [0, 1].
background.y = (IsNearZero(m_Background.g) ? m_Ember.m_Background.g : m_Background.g) / (vibGamCount / T(256.0));
background.z = (IsNearZero(m_Background.b) ? m_Ember.m_Background.b : m_Background.b) / (vibGamCount / T(256.0));
background.x = (IsNearZero(m_Background.r) ? bucketT(m_Ember.m_Background.r) : m_Background.r) / (vibGamCount / bucketT(256.0));//Background is [0, 1].
background.y = (IsNearZero(m_Background.g) ? bucketT(m_Ember.m_Background.g) : m_Background.g) / (vibGamCount / bucketT(256.0));
background.z = (IsNearZero(m_Background.b) ? bucketT(m_Ember.m_Background.b) : m_Background.b) / (vibGamCount / bucketT(256.0));
}
/// <summary>
@ -1570,7 +1569,7 @@ void Renderer<T, bucketT>::AddToAccum(const tvec4<bucketT, glm::defaultp>& bucke
/// Because this code is used in both early and late clipping, a few extra arguments are passed
/// to specify what actions to take. Coupled with an additional template argument, this allows
/// using one function to perform all color clipping, gamma correction and final accumulation.
/// Template argument accumT is expected to match T for the case of early clipping, byte for late clip for
/// Template argument accumT is expected to match bucketT for the case of early clipping, byte for late clip for
/// images with one byte per channel and unsigned short for images with two bytes per channel.
/// </summary>
/// <param name="bucket">The pixel to correct</param>
@ -1583,11 +1582,10 @@ void Renderer<T, bucketT>::AddToAccum(const tvec4<bucketT, glm::defaultp>& bucke
/// <param name="correctedChannels">The storage space for the corrected values to be written to</param>
template <typename T, typename bucketT>
template <typename accumT>
void Renderer<T, bucketT>::GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket, Color<T>& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels)
void Renderer<T, bucketT>::GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket, Color<bucketT>& background, bucketT g, bucketT linRange, bucketT vibrancy, bool doAlpha, bool scale, accumT* correctedChannels)
{
T alpha, ls, a;
bucketT newRgb[3];//Would normally use a Color<bucketT>, but don't want to call a needless constructor every time this function is called, which is once per pixel.
static T scaleVal = (numeric_limits<accumT>::max() + 1) / T(256.0);
bucketT alpha, ls, a, newRgb[3];//Would normally use a Color<bucketT>, but don't want to call a needless constructor every time this function is called, which is once per pixel.
static bucketT scaleVal = (numeric_limits<accumT>::max() + 1) / bucketT(256.0);
if (bucket.a <= 0)
{
@ -1596,20 +1594,20 @@ void Renderer<T, bucketT>::GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket
}
else
{
alpha = Palette<T>::CalcAlpha(bucket.a, g, linRange);
ls = vibrancy * T(255) * alpha / bucket.a;
ClampRef<T>(alpha, 0, 1);
alpha = Palette<bucketT>::CalcAlpha(bucket.a, g, linRange);
ls = vibrancy * 255 * alpha / bucket.a;
ClampRef<bucketT>(alpha, 0, 1);
}
Palette<T>::template CalcNewRgb<bucketT>(&bucket[0], ls, HighlightPower(), newRgb);
Palette<bucketT>::template CalcNewRgb<bucketT>(&bucket[0], ls, HighlightPower(), newRgb);
for (glm::length_t rgbi = 0; rgbi < 3; rgbi++)
{
a = newRgb[rgbi] + ((T(1.0) - vibrancy) * T(255) * pow(T(bucket[rgbi]), g));
a = newRgb[rgbi] + ((1 - vibrancy) * 255 * pow(bucket[rgbi], g));
if (NumChannels() <= 3 || !Transparency())
{
a += ((T(1.0) - alpha) * background[rgbi]);
a += (1 - alpha) * background[rgbi];
}
else
{
@ -1621,14 +1619,14 @@ void Renderer<T, bucketT>::GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket
if (!scale)
{
correctedChannels[rgbi] = accumT(Clamp<T>(a, 0, 255));//Early clip, just assign directly.
correctedChannels[rgbi] = accumT(Clamp<bucketT>(a, 0, 255));//Early clip, just assign directly.
}
else
{
if (m_CurvesSet)
CurveAdjust(a, rgbi + 1);
correctedChannels[rgbi] = accumT(Clamp<T>(a, 0, 255) * scaleVal);//Final accum, multiply by 1 for 8 bpc, or 256 for 16 bpc.
correctedChannels[rgbi] = accumT(Clamp<bucketT>(a, 0, 255) * scaleVal);//Final accum, multiply by 1 for 8 bpc, or 256 for 16 bpc.
}
}
@ -1644,10 +1642,10 @@ void Renderer<T, bucketT>::GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket
}
template <typename T, typename bucketT>
void Renderer<T, bucketT>::CurveAdjust(T& a, const glm::length_t& index)
void Renderer<T, bucketT>::CurveAdjust(bucketT& a, const glm::length_t& index)
{
size_t tempIndex = size_t(Clamp<T>(a, 0, COLORMAP_LENGTH_MINUS_1));
size_t tempIndex2 = size_t(Clamp<T>(m_Csa[tempIndex].x, 0, COLORMAP_LENGTH_MINUS_1));
size_t tempIndex = size_t(Clamp<bucketT>(a, 0, COLORMAP_LENGTH_MINUS_1));
size_t tempIndex2 = size_t(Clamp<bucketT>(m_Csa[tempIndex].x, 0, COLORMAP_LENGTH_MINUS_1));
a = std::round(m_Csa[tempIndex2][index]);
}
@ -1658,6 +1656,6 @@ void Renderer<T, bucketT>::CurveAdjust(T& a, const glm::length_t& index)
template EMBER_API class Renderer<float, float>;
#ifdef DO_DOUBLE
template EMBER_API class Renderer<double, double>;
template EMBER_API class Renderer<double, float>;
#endif
}

View File

@ -87,12 +87,12 @@ public:
inline T Scale() const;
inline T PixelsPerUnitX() const;
inline T PixelsPerUnitY() const;
inline T K1() const;
inline T K2() const;
inline bucketT K1() const;
inline bucketT K2() const;
inline const CarToRas<T>* CoordMap() const;
inline tvec4<bucketT, glm::defaultp>* HistBuckets();
inline tvec4<bucketT, glm::defaultp>* AccumulatorBuckets();
inline SpatialFilter<T>* GetSpatialFilter();
inline SpatialFilter<bucketT>* GetSpatialFilter();
inline TemporalFilter<T>* GetTemporalFilter();
//Virtual renderer properties overridden from RendererBase, getters only.
@ -116,12 +116,12 @@ public:
inline T CenterY() const;
inline T Rotate() const;
inline T Hue() const;
inline T Brightness() const;
inline T Contrast() const;
inline T Gamma() const;
inline T Vibrancy() const;
inline T GammaThresh() const;
inline T HighlightPower() const;
inline bucketT Brightness() const;
inline bucketT Contrast() const;
inline bucketT Gamma() const;
inline bucketT Vibrancy() const;
inline bucketT GammaThresh() const;
inline bucketT HighlightPower() const;
inline Color<T> Background() const;
inline const Xform<T>* Xforms() const;
inline Xform<T>* NonConstXforms();
@ -146,14 +146,14 @@ public:
protected:
//Non-virtual functions that might be needed by a derived class.
void PrepFinalAccumVals(Color<T>& background, T& g, T& linRange, T& vibrancy);
void PrepFinalAccumVals(Color<bucketT>& background, bucketT& g, bucketT& linRange, bucketT& vibrancy);
private:
//Miscellaneous non-virtual functions used only in this class.
void Accumulate(QTIsaac<ISAAC_SIZE, ISAAC_INT>& rand, Point<T>* samples, size_t sampleCount, const Palette<bucketT>* palette);
/*inline*/ void AddToAccum(const tvec4<bucketT, glm::defaultp>& bucket, intmax_t i, intmax_t ii, intmax_t j, intmax_t jj);
template <typename accumT> void GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket, Color<T>& background, T g, T linRange, T vibrancy, bool doAlpha, bool scale, accumT* correctedChannels);
void CurveAdjust(T& a, const glm::length_t& index);
template <typename accumT> void GammaCorrection(tvec4<bucketT, glm::defaultp>& bucket, Color<bucketT>& background, bucketT g, bucketT linRange, bucketT vibrancy, bool doAlpha, bool scale, accumT* correctedChannels);
void CurveAdjust(bucketT& a, const glm::length_t& index);
protected:
T m_Scale;
@ -164,12 +164,12 @@ protected:
T m_LowerLeftY;
T m_UpperRightX;
T m_UpperRightY;
T m_K1;
T m_K2;
T m_Vibrancy;//Accumulate these after each temporal sample.
T m_Gamma;
bucketT m_K1;
bucketT m_K2;
bucketT m_Vibrancy;//Accumulate these after each temporal sample.
bucketT m_Gamma;
T m_ScaledQuality;
Color<T> m_Background;
Color<bucketT> m_Background;//This is a scaled copy of the m_Background member of m_Ember, but with a type of bucketT.
Affine2D<T> m_RotMat;
Ember<T> m_Ember;
Ember<T> m_TempEmber;
@ -182,9 +182,9 @@ protected:
Palette<bucketT> m_Dmap, m_Csa;
vector<tvec4<bucketT, glm::defaultp>> m_HistBuckets;
vector<tvec4<bucketT, glm::defaultp>> m_AccumulatorBuckets;
unique_ptr<SpatialFilter<T>> m_SpatialFilter;
unique_ptr<SpatialFilter<bucketT>> m_SpatialFilter;
unique_ptr<TemporalFilter<T>> m_TemporalFilter;
unique_ptr<DensityFilter<T>> m_DensityFilter;
unique_ptr<DensityFilter<bucketT>> m_DensityFilter;
vector<vector<Point<T>>> m_Samples;
EmberToXml<T> m_EmberToXml;
};
@ -192,9 +192,4 @@ protected:
//This class had to be implemented in a cpp file because the compiler was breaking.
//So the explicit instantiation must be declared here rather than in Ember.cpp where
//all of the other classes are done.
//template EMBER_API class Renderer<float, float>;
//#ifdef DO_DOUBLE
// template EMBER_API class Renderer<double, double>;
//#endif
}

View File

@ -384,12 +384,8 @@ public:
}
else//Randomize palette only.
{
Palette<T> palette;
if (m_PaletteList.Size())
palette = *m_PaletteList.GetRandomPalette();
palette.MakeHueAdjustedPalette(ember.m_Palette, ember.m_Hue);
ember.m_Palette = *m_PaletteList.GetRandomPalette();
//If the palette retrieval fails, skip the mutation.
if (ember.m_Palette.m_Index >= 0)
@ -398,8 +394,7 @@ public:
}
else
{
palette.Clear(false);
ember.m_Palette = palette;
ember.m_Palette.Clear(false);
cout << "Failure getting random palette, palette set to white\n";
}
}
@ -638,12 +633,10 @@ public:
};
ember.Clear();
ember.m_Hue = (m_Rand.Rand() & 7) ? 0 : m_Rand.Frand01<T>();
if (m_PaletteList.Size())
palette = *m_PaletteList.GetRandomPalette();
ember.m_Palette = *m_PaletteList.GetRandomPalette();
palette.MakeHueAdjustedPalette(ember.m_Palette, ember.m_Hue);
ember.m_Time = 0;
ember.m_Interp = EMBER_INTERP_LINEAR;
ember.m_PaletteInterp = INTERP_HSV;
@ -922,16 +915,9 @@ public:
if (changePalette)
{
Palette<T>* palette = nullptr;
ember.m_Hue = 0.0;
if (m_PaletteList.Size())
palette = m_PaletteList.GetRandomPalette();
if (palette)
{
palette->MakeHueAdjustedPalette(ember.m_Palette, ember.m_Hue);
ember.m_Palette = *m_PaletteList.GetRandomPalette();
}
else
{

View File

@ -522,10 +522,10 @@ private:
if (currentEmber.PaletteIndex() != -1)
{
if (!m_PaletteList.GetHueAdjustedPalette(PaletteList<T>::m_DefaultFilename, currentEmber.PaletteIndex(), currentEmber.m_Hue, currentEmber.m_Palette))
{
if (auto pal = m_PaletteList.GetPalette(PaletteList<T>::m_DefaultFilename, currentEmber.PaletteIndex()))
currentEmber.m_Palette = *pal;
else
m_ErrorReport.push_back(string(loc) + " : Error assigning palette with index " + Itos(currentEmber.PaletteIndex()));
}
}
//if (!Interpolater<T>::InterpMissingColors(currentEmber.m_Palette.m_Entries))
@ -712,11 +712,6 @@ private:
currentEmber.m_Background[1] = T(vals[1]);
currentEmber.m_Background[2] = T(vals[2]);
}
else if (!Compare(curAtt->name, "hue"))
{
Atof(attStr, currentEmber.m_Hue);
currentEmber.m_Hue = fmod(currentEmber.m_Hue, T(0.5));//Orig did fmod 1, but want it in the range -0.5 - 0.5.
}
else if (!Compare(curAtt->name, "curves"))
{
stringstream ss(attStr);
@ -1055,8 +1050,6 @@ private:
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_DEPTH_BLUR, motion);
else if (!Compare(curAtt->name, "rotate"))
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_ROTATE, motion);
else if (!Compare(curAtt->name, "hue"))
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_HUE, motion);
else if (!Compare(curAtt->name, "brightness"))
ret = ret && AttToEmberMotionFloat(att, attStr, FLAME_MOTION_BRIGHTNESS, motion);
else if (!Compare(curAtt->name, "gamma"))