mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-07-02 06:16:17 -04:00
--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:
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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"))
|
||||
|
Reference in New Issue
Block a user