mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-07-01 05:46:06 -04:00
--User changes
-Always force times of each flame to increase from zero when saving a file. -Remove check for times when doing a sequence in EmberGenome because the original times are never used there. --Bug fixes -Multi-GPU synchronization was not actually thread safe and was likely doing less iters than requested. It is now properly synchronized. --Code changes -Optimize Interpolater by making it a non-static class by adding some members used for caching values during interpolation. -Cache values in SheepTools as well, which was already a non-static class. -General cleanup.
This commit is contained in:
@ -78,22 +78,9 @@ public:
|
||||
{
|
||||
auto prev = embers.begin();
|
||||
|
||||
//Check to see if there are valid times by checking if any differed.
|
||||
//If so, assume they were intentionally entered times.
|
||||
for (auto it = Advance(embers.begin(), 1); it != embers.end(); ++it)
|
||||
{
|
||||
if (it->m_Time != prev->m_Time)
|
||||
{
|
||||
hasTimes = true;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = it;
|
||||
}
|
||||
|
||||
if (!hasTimes)
|
||||
for (auto& ember : embers)
|
||||
ember.m_Time = t++;
|
||||
//Always ensure times make sense.
|
||||
for (auto& ember : embers)
|
||||
ember.m_Time = t++;
|
||||
|
||||
if ((append && start) || !append)
|
||||
{
|
||||
|
@ -376,7 +376,7 @@ public:
|
||||
/// <param name="time">The time position in the vector specifying the point of interpolation</param>
|
||||
/// <param name="stagger">Stagger if > 0</param>
|
||||
/// <param name="result">The interpolated result</param>
|
||||
static void Interpolate(const vector<Ember<T>>& embers, T time, T stagger, Ember<T>& result)
|
||||
void Interpolate(const vector<Ember<T>>& embers, T time, T stagger, Ember<T>& result)
|
||||
{
|
||||
Interpolate(embers.data(), embers.size(), time, stagger, result);
|
||||
}
|
||||
@ -389,7 +389,7 @@ public:
|
||||
/// <param name="time">The time position in the vector specifying the point of interpolation</param>
|
||||
/// <param name="stagger">Stagger if > 0</param>
|
||||
/// <param name="result">The interpolated result</param>
|
||||
static void Interpolate(const Ember<T>* embers, size_t size, T time, T stagger, Ember<T>& result)
|
||||
void Interpolate(const Ember<T>* embers, size_t size, T time, T stagger, Ember<T>& result)
|
||||
{
|
||||
if (size == 1)
|
||||
{
|
||||
@ -398,8 +398,6 @@ public:
|
||||
}
|
||||
|
||||
size_t i1, i2;
|
||||
vector<T> c(2);
|
||||
Ember<T> localEmbers[4];
|
||||
bool smoothFlag = false;
|
||||
|
||||
if (embers[0].m_Time >= time)
|
||||
@ -423,31 +421,31 @@ public:
|
||||
i2 = i1 + 1;
|
||||
}
|
||||
|
||||
c[0] = (embers[i2].m_Time - time) / (embers[i2].m_Time - embers[i1].m_Time);
|
||||
c[1] = 1 - c[0];
|
||||
m_Coeffs[0] = (embers[i2].m_Time - time) / (embers[i2].m_Time - embers[i1].m_Time);
|
||||
m_Coeffs[1] = 1 - m_Coeffs[0];
|
||||
|
||||
//To interpolate the xforms, make copies of the source embers
|
||||
//and ensure that they both have the same number of xforms before progressing.
|
||||
if (embers[i1].m_Interp == eInterp::EMBER_INTERP_LINEAR)
|
||||
{
|
||||
Align(&embers[i1], &localEmbers[0], 2);
|
||||
Align(&embers[i1], &m_Embers[0], 2);
|
||||
smoothFlag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i1 == 0)
|
||||
{
|
||||
Align(&embers[i1], &localEmbers[0], 2);
|
||||
Align(&embers[i1], &m_Embers[0], 2);
|
||||
smoothFlag = false;
|
||||
}
|
||||
else if (i2 == size - 1)
|
||||
{
|
||||
Align(&embers[i1], &localEmbers[0], 2);
|
||||
Align(&embers[i1], &m_Embers[0], 2);
|
||||
smoothFlag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Align(&embers[i1 - 1], &localEmbers[0], 4);//Should really be doing some sort of checking here to ensure the ember vectors have 4 elements.
|
||||
Align(&embers[i1 - 1], &m_Embers[0], 4);//Should really be doing some sort of checking here to ensure the ember vectors have 4 elements.
|
||||
smoothFlag = true;
|
||||
}
|
||||
}
|
||||
@ -458,9 +456,9 @@ public:
|
||||
result.m_PaletteInterp = ePaletteInterp::INTERP_HSV;
|
||||
|
||||
if (!smoothFlag)
|
||||
result.Interpolate(&localEmbers[0], 2, c, stagger);
|
||||
result.Interpolate(&m_Embers[0], 2, m_Coeffs, stagger);
|
||||
else
|
||||
result.InterpolateCatmullRom(&localEmbers[0], 4, c[1]);
|
||||
result.InterpolateCatmullRom(&m_Embers[0], 4, m_Coeffs[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -492,9 +490,9 @@ public:
|
||||
{
|
||||
for (size_t i = 0; i < source->TotalVariationCount(); i++)//Iterate through the first xform's variations.
|
||||
{
|
||||
Variation<T>* var = source->GetVariation(i);//Grab the variation at index in in the first xform.
|
||||
Variation<T>* var2 = dest->GetVariationById(var->VariationId());//See if the same variation exists in the second xform.
|
||||
ParametricVariation<T>* parVar = dynamic_cast<ParametricVariation<T>*>(var);//Parametric cast of the first var for later.
|
||||
auto var = source->GetVariation(i);//Grab the variation at index in in the first xform.
|
||||
auto var2 = dest->GetVariationById(var->VariationId());//See if the same variation exists in the second xform.
|
||||
auto parVar = dynamic_cast<ParametricVariation<T>*>(var);//Parametric cast of the first var for later.
|
||||
|
||||
if (!var2)//Only take action if the second xform did not contain this variation.
|
||||
{
|
||||
@ -502,7 +500,7 @@ public:
|
||||
{
|
||||
if (parVar)
|
||||
{
|
||||
Variation<T>* parVarCopy = parVar->Copy();
|
||||
auto parVarCopy = parVar->Copy();
|
||||
|
||||
if (clearWeights)
|
||||
parVarCopy->m_Weight = 0;
|
||||
@ -512,7 +510,7 @@ public:
|
||||
}
|
||||
else//Add regardless of type.
|
||||
{
|
||||
Variation<T>* varCopy = var->Copy();
|
||||
auto varCopy = var->Copy();
|
||||
|
||||
if (clearWeights)
|
||||
varCopy->m_Weight = 0;
|
||||
@ -732,8 +730,7 @@ public:
|
||||
{
|
||||
for (size_t col = 0; col < 2; col++)
|
||||
{
|
||||
int sym0, sym1;
|
||||
int padSymFlag;
|
||||
bool sym0, sym1, padSymFlag = false;
|
||||
d = cxang[k][col] - cxang[k - 1][col];
|
||||
|
||||
//Adjust to avoid the -pi/pi discontinuity.
|
||||
@ -745,7 +742,6 @@ public:
|
||||
//If this is an asymmetric case, store the NON-symmetric angle
|
||||
//Check them pairwise and store the reference angle in the second
|
||||
//to avoid overwriting if asymmetric on both sides.
|
||||
padSymFlag = 0;
|
||||
sym0 = (embers[k - 1].GetXform(xfi)->m_Animate == 0 || (embers[k - 1].GetXform(xfi)->Empty() && padSymFlag));
|
||||
sym1 = (embers[k ].GetXform(xfi)->m_Animate == 0 || (embers[k ].GetXform(xfi)->Empty() && padSymFlag));
|
||||
|
||||
@ -936,5 +932,9 @@ public:
|
||||
|
||||
return ad > bd;
|
||||
}
|
||||
|
||||
private:
|
||||
vector<T> m_Coeffs = vector<T>(2);
|
||||
Ember<T> m_Embers[4];
|
||||
};
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
|
||||
//it.Tic();
|
||||
//Interpolate.
|
||||
if (m_EmbersP->size() > 1)
|
||||
Interpolater<T>::Interpolate(*m_EmbersP, T(time), 0, m_Ember);
|
||||
m_Interpolater.Interpolate(*m_EmbersP, T(time), 0, m_Ember);
|
||||
|
||||
//it.Toc("Interp 1");
|
||||
|
||||
@ -454,7 +454,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
|
||||
//Additional interpolation will be done in the temporal samples loop.
|
||||
//it.Tic();
|
||||
if (m_EmbersP->size() > 1)
|
||||
Interpolater<T>::Interpolate(*m_EmbersP, deTime, 0, m_Ember);
|
||||
m_Interpolater.Interpolate(*m_EmbersP, deTime, 0, m_Ember);
|
||||
|
||||
//it.Toc("Interp 2");
|
||||
ClampGteRef<T>(m_Ember.m_MinRadDE, 0);
|
||||
@ -479,7 +479,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
|
||||
//Interpolate again.
|
||||
//it.Tic();
|
||||
if (TemporalSamples() > 1 && m_EmbersP->size() > 1)
|
||||
Interpolater<T>::Interpolate(*m_EmbersP, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
|
||||
m_Interpolater.Interpolate(*m_EmbersP, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
|
||||
|
||||
//it.Toc("Interp 3");
|
||||
|
||||
|
@ -184,6 +184,7 @@ private:
|
||||
protected:
|
||||
vector<Ember<T>>* m_EmbersP = &m_Embers;
|
||||
vector<Ember<T>> m_ThreadEmbers;
|
||||
Interpolater<T> m_Interpolater;
|
||||
CarToRas<T> m_CarToRas;
|
||||
unique_ptr<StandardIterator<T>> m_StandardIterator = make_unique<StandardIterator<T>>();
|
||||
unique_ptr<XaosIterator<T>> m_XaosIterator = make_unique<XaosIterator<T>>();
|
||||
|
@ -452,14 +452,13 @@ public:
|
||||
else if (crossMode == eCrossMode::CROSS_INTERPOLATE)
|
||||
{
|
||||
//Linearly interpolate somewhere between the two.
|
||||
Ember<T> parents[2];
|
||||
//t = 0.5;//If you ever need to test.
|
||||
t = m_Rand.Frand01<T>();
|
||||
parents[0] = ember0;
|
||||
parents[1] = ember1;
|
||||
parents[0].m_Time = T(0);
|
||||
parents[1].m_Time = T(1);
|
||||
Interpolater<T>::Interpolate(parents, 2, t, 0, emberOut);
|
||||
m_Parents[0] = ember0;
|
||||
m_Parents[1] = ember1;
|
||||
m_Parents[0].m_Time = T(0);
|
||||
m_Parents[1].m_Time = T(1);
|
||||
m_Interpolater.Interpolate(m_Parents, 2, t, 0, emberOut);
|
||||
|
||||
for (i = 0; i < emberOut.TotalXformCount(); i++)
|
||||
emberOut.GetTotalXform(i)->DeleteMotionElements();
|
||||
@ -990,21 +989,20 @@ public:
|
||||
void Edge(Ember<T>* embers, Ember<T>& result, T blend, bool seqFlag)
|
||||
{
|
||||
size_t i, si;
|
||||
Ember<T> spun[2], prealign[2];
|
||||
|
||||
//Insert motion magic here :
|
||||
//If there are motion elements, modify the contents of
|
||||
//the result xforms before rotate is called.
|
||||
for (si = 0; si < 2; si++)
|
||||
{
|
||||
prealign[si] = embers[si];
|
||||
m_EdgePrealign[si] = embers[si];
|
||||
|
||||
for (i = 0; i < embers[si].TotalXformCount(); i++)
|
||||
{
|
||||
auto xform = embers[si].GetTotalXform(i);
|
||||
|
||||
if (!xform->m_Motion.empty())
|
||||
xform->ApplyMotion(*(prealign[si].GetTotalXform(i)), blend);//Apply motion parameters to result.xform[i] using blend parameter.
|
||||
xform->ApplyMotion(*(m_EdgePrealign[si].GetTotalXform(i)), blend);//Apply motion parameters to result.xform[i] using blend parameter.
|
||||
}
|
||||
}
|
||||
|
||||
@ -1012,20 +1010,20 @@ public:
|
||||
//This keeps the original interpolation type intact.
|
||||
if (seqFlag && blend == 0)
|
||||
{
|
||||
result = prealign[0];
|
||||
result = m_EdgePrealign[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Align what's going to be interpolated.
|
||||
Interpolater<T>::Align(prealign, spun, 2);
|
||||
spun[0].m_Time = 0;
|
||||
spun[1].m_Time = 1;
|
||||
Interpolater<T>::Align(m_EdgePrealign, m_EdgeSpun, 2);
|
||||
m_EdgeSpun[0].m_Time = 0;
|
||||
m_EdgeSpun[1].m_Time = 1;
|
||||
//Call this first to establish the asymmetric reference angles.
|
||||
Interpolater<T>::AsymmetricRefAngles(spun, 2);
|
||||
Interpolater<T>::AsymmetricRefAngles(m_EdgeSpun, 2);
|
||||
//Rotate the aligned xforms.
|
||||
spun[0].RotateAffines(-blend * 360);
|
||||
spun[1].RotateAffines(-blend * 360);
|
||||
Interpolater<T>::Interpolate(spun, 2, m_Smooth ? Interpolater<T>::Smoother(blend) : blend, m_Stagger, result);
|
||||
m_EdgeSpun[0].RotateAffines(-blend * 360);
|
||||
m_EdgeSpun[1].RotateAffines(-blend * 360);
|
||||
m_Interpolater.Interpolate(m_EdgeSpun, 2, m_Smooth ? Interpolater<T>::Smoother(blend) : blend, m_Stagger, result);
|
||||
}
|
||||
|
||||
//Make sure there are no motion elements in the result.
|
||||
@ -1340,6 +1338,10 @@ private:
|
||||
vector<uint> m_Hist;
|
||||
EmberToXml<T> m_EmberToXml;
|
||||
Iterator<T>* m_Iterator;
|
||||
Interpolater<T> m_Interpolater;
|
||||
Ember<T> m_Parents[2];
|
||||
Ember<T> m_EdgeSpun[2];
|
||||
Ember<T> m_EdgePrealign[2];
|
||||
unique_ptr<StandardIterator<T>> m_StandardIterator = make_unique<StandardIterator<T>>();
|
||||
unique_ptr<XaosIterator<T>> m_XaosIterator = make_unique<XaosIterator<T>>();
|
||||
unique_ptr<Renderer<T, bucketT>> m_Renderer;
|
||||
|
@ -1028,6 +1028,26 @@ static vector<string> Split(const string& str, char del)
|
||||
return vec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thin wrapper around joining a thread.
|
||||
/// </summary>
|
||||
/// <param name="th">The thread to join</param>
|
||||
static void Join(std::thread& th)
|
||||
{
|
||||
if (th.joinable())
|
||||
th.join();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thin wrapper around joining a vector of threads.
|
||||
/// </summary>
|
||||
/// <param name="vec">The vector of threads to join</param>
|
||||
static void Join(std::vector<std::thread>& vec)
|
||||
{
|
||||
for (auto& it : vec)
|
||||
Join(it);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a character pointer to a version string composed of the EMBER_OS and EMBER_VERSION values.
|
||||
/// </summary>
|
||||
|
Reference in New Issue
Block a user