--User changes

-Edits will not save back to the file in memory on render completion when preview renderer is running.

--Bug fixes
 -dc_perlin was crashing on Nvidia when using SP.
 -Duplicate images were randomly getting added to the file in memory.
 -Crash when opening an Xml with less than 2 flames in it.

--Code changes
 -Use raw array of floats in OpenCL for perlin noise, rather than float3/double3.
 -Add some default cases to dc_perlin.
 -Redo singleton pattern yet again. Deriving from a templated Singleton<T> class was creating a separate instance per module. Now only one instance of each type will ever be created and it will be wrapped in a shared_ptr which guarantees its deletion as main() exits.
This commit is contained in:
mfeemster
2016-04-13 20:59:57 -07:00
parent 7715910362
commit 0fbea60026
29 changed files with 264 additions and 220 deletions

View File

@ -239,7 +239,7 @@ public:
ember.m_FinalXform.m_ColorSpeed = 0;
ember.m_FinalXform.m_Motion.clear();
ember.m_FinalXform.ClearAndDeleteVariations();
ember.m_FinalXform.AddVariation(m_VariationList.GetVariationCopy(eVariationId::VAR_LINEAR, 0));//Do this so it doesn't appear empty.
ember.m_FinalXform.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR, 0));//Do this so it doesn't appear empty.
}
}
@ -1036,7 +1036,7 @@ public:
m_Xforms[i].m_Affine.D(0);
m_Xforms[i].m_Affine.E(1);
m_Xforms[i].m_Affine.F(0);
m_Xforms[i].AddVariation(m_VariationList.GetVariationCopy(eVariationId::VAR_LINEAR));
m_Xforms[i].AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
result++;
sym = -sym;
}
@ -1058,7 +1058,7 @@ public:
m_Xforms[i].m_Affine.E(m_Xforms[i].m_Affine.A());
m_Xforms[i].m_Affine.C(0);
m_Xforms[i].m_Affine.F(0);
m_Xforms[i].AddVariation(m_VariationList.GetVariationCopy(eVariationId::VAR_LINEAR));
m_Xforms[i].AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
result++;
}
@ -1688,7 +1688,7 @@ private:
Xform<T> m_FinalXform;
//Single global reference to create variations with.
VariationList<T>& m_VariationList = VariationList<T>::Instance();
shared_ptr<VariationList<T>> m_VariationList = VariationList<T>::Instance();
/// <summary>
/// Interpolation function that takes the address of a member variable of type T as a template parameter.

View File

@ -44,7 +44,7 @@ public:
bool currentFinal, final = sourceEmbers[0].UseFinalXform();
size_t i, xf, currentCount, maxCount = sourceEmbers[0].XformCount();
Xform<T>* destOtherXform;
VariationList<T>& variationList(VariationList<T>::Instance());
auto variationList = VariationList<T>::Instance();
//Determine the max number of xforms present in sourceEmbers.
//Also check if final xforms are used in any of them.
@ -138,7 +138,7 @@ public:
destOtherXform->GetVariationById(eVariationId::VAR_WEDGE_SPH) ||
destOtherXform->GetVariationById(eVariationId::VAR_WEDGE_JULIA))
{
destXform->AddVariation(variationList.GetVariationCopy(eVariationId::VAR_LINEAR, -1));
destXform->AddVariation(variationList->GetVariationCopy(eVariationId::VAR_LINEAR, -1));
//Set the coefs appropriately.
destXform->m_Affine.A(-1);
destXform->m_Affine.D(0);
@ -167,7 +167,7 @@ public:
if (destOtherXform->GetVariationById(eVariationId::VAR_RECTANGLES))
{
if (auto var = variationList.GetParametricVariationCopy(eVariationId::VAR_RECTANGLES))
if (auto var = variationList->GetParametricVariationCopy(eVariationId::VAR_RECTANGLES))
{
var->SetParamVal("rectangles_x", 0);
var->SetParamVal("rectangles_y", 0);
@ -179,7 +179,7 @@ public:
if (destOtherXform->GetVariationById(eVariationId::VAR_RINGS2))
{
if (auto var = variationList.GetParametricVariationCopy(eVariationId::VAR_RINGS2))
if (auto var = variationList->GetParametricVariationCopy(eVariationId::VAR_RINGS2))
{
var->SetParamVal("rings2_val", 0);
destXform->AddVariation(var);
@ -190,13 +190,13 @@ public:
if (destOtherXform->GetVariationById(eVariationId::VAR_FAN2))
{
destXform->AddVariation(variationList.GetVariationCopy(eVariationId::VAR_FAN2));
destXform->AddVariation(variationList->GetVariationCopy(eVariationId::VAR_FAN2));
found++;
}
if (destOtherXform->GetVariationById(eVariationId::VAR_BLOB))
{
if (auto var = variationList.GetParametricVariationCopy(eVariationId::VAR_BLOB))
if (auto var = variationList->GetParametricVariationCopy(eVariationId::VAR_BLOB))
{
var->SetParamVal("blob_low", 1);
destXform->AddVariation(var);
@ -207,13 +207,13 @@ public:
if (destOtherXform->GetVariationById(eVariationId::VAR_PERSPECTIVE))
{
destXform->AddVariation(variationList.GetVariationCopy(eVariationId::VAR_PERSPECTIVE));
destXform->AddVariation(variationList->GetVariationCopy(eVariationId::VAR_PERSPECTIVE));
found++;
}
if (destOtherXform->GetVariationById(eVariationId::VAR_CURL))
{
if (auto var = variationList.GetParametricVariationCopy(eVariationId::VAR_CURL))
if (auto var = variationList->GetParametricVariationCopy(eVariationId::VAR_CURL))
{
var->SetParamVal("curl_c1", 0);
destXform->AddVariation(var);
@ -224,7 +224,7 @@ public:
if (destOtherXform->GetVariationById(eVariationId::VAR_SUPER_SHAPE))
{
if (auto var = variationList.GetParametricVariationCopy(eVariationId::VAR_SUPER_SHAPE))
if (auto var = variationList->GetParametricVariationCopy(eVariationId::VAR_SUPER_SHAPE))
{
var->SetParamVal("super_shape_n1", 2);
var->SetParamVal("super_shape_n2", 2);
@ -254,13 +254,13 @@ public:
if (destOtherXform->GetVariationById(eVariationId::VAR_FAN))
{
destXform->AddVariation(variationList.GetVariationCopy(eVariationId::VAR_FAN));
destXform->AddVariation(variationList->GetVariationCopy(eVariationId::VAR_FAN));
found++;
}
if (destOtherXform->GetVariationById(eVariationId::VAR_RINGS))
{
destXform->AddVariation(variationList.GetVariationCopy(eVariationId::VAR_RINGS));
destXform->AddVariation(variationList->GetVariationCopy(eVariationId::VAR_RINGS));
found++;
}
}
@ -280,7 +280,7 @@ public:
//If there still are no matches, switch back to linear.
if (found == 0)
{
destXform->AddVariation(variationList.GetVariationCopy(eVariationId::VAR_LINEAR));
destXform->AddVariation(variationList->GetVariationCopy(eVariationId::VAR_LINEAR));
}
else if (found > 0)
{

View File

@ -83,9 +83,9 @@ public:
Xform<T> xform1(T(0.25), T(1), T(0.5), T(1), T(0.5), T(0), T(0), T(0.5), T(0.5), T(0.25));
Xform<T> xform2(T(0.25), T(0.66), T(0.5), T(1), T(0.5), T(0), T(0), T(0.5), T(-0.5), T(0.25));
Xform<T> xform3(T(0.25), T(0.33), T(0.5), T(1), T(0.5), T(0), T(0), T(0.5), T(0.0), T(-0.5));
xform1.AddVariation(m_VariationList.GetVariationCopy(eVariationId::VAR_LINEAR));
xform2.AddVariation(m_VariationList.GetVariationCopy(eVariationId::VAR_LINEAR));
xform3.AddVariation(m_VariationList.GetVariationCopy(eVariationId::VAR_LINEAR));
xform1.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
xform2.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
xform3.AddVariation(m_VariationList->GetVariationCopy(eVariationId::VAR_LINEAR));
ember.AddXform(xform1);
ember.AddXform(xform2);
ember.AddXform(xform3);
@ -599,7 +599,7 @@ public:
bool postid, addfinal = false;
int var, samed, multid, samepost;
glm::length_t i, j, k, n;
size_t varCount = m_VariationList.Size();
size_t varCount = m_VariationList->Size();
Palette<T> palette;
static size_t xformDistrib[] =
{
@ -683,12 +683,12 @@ public:
if (var > -1)
{
if (xform->TotalVariationCount() < maxVars)
xform->AddVariation(m_VariationList.GetVariation(var)->Copy());//Use only one variation specified for all xforms.
xform->AddVariation(m_VariationList->GetVariation(var)->Copy());//Use only one variation specified for all xforms.
}
else if (multid && var == -1)
{
if (xform->TotalVariationCount() < maxVars)
xform->AddVariation(m_VariationList.GetVariation(m_Rand.Rand() % varCount)->Copy());//Choose a random var for this xform.
xform->AddVariation(m_VariationList->GetVariation(m_Rand.Rand() % varCount)->Copy());//Choose a random var for this xform.
}
else
{
@ -721,7 +721,7 @@ public:
if (var != -2)
{
//Pick a random variation and use a random weight from 0-1.
Variation<T>* v = m_VariationList.GetVariationCopy(static_cast<size_t>(m_Rand.Rand() % varCount), m_Rand.Frand<T>(T(0.001), 1));
Variation<T>* v = m_VariationList->GetVariationCopy(static_cast<size_t>(m_Rand.Rand() % varCount), m_Rand.Frand<T>(T(0.001), 1));
if (v && !xform->AddVariation(v))
delete v;//It already existed and therefore was not added.
@ -729,7 +729,7 @@ public:
else
{
//Pick a random variation from the suppled IDs and use a random weight from 0-1.
Variation<T>* v = m_VariationList.GetVariationCopy(useVars[m_Rand.Rand() % useVars.size()], m_Rand.Frand<T>(T(0.001), 1));
Variation<T>* v = m_VariationList->GetVariationCopy(useVars[m_Rand.Rand() % useVars.size()], m_Rand.Frand<T>(T(0.001), 1));
if (v && !xform->AddVariation(v))
delete v;
@ -759,12 +759,12 @@ public:
if (var != -2)
{
//Pick a random variation and use a random weight from 0-1.
xform->AddVariation(m_VariationList.GetVariationCopy(static_cast<size_t>(m_Rand.Rand() % varCount), m_Rand.Frand<T>(T(0.001), 1)));
xform->AddVariation(m_VariationList->GetVariationCopy(static_cast<size_t>(m_Rand.Rand() % varCount), m_Rand.Frand<T>(T(0.001), 1)));
}
else
{
//Pick a random variation from the suppled IDs and use a random weight from 0-1.
xform->AddVariation(m_VariationList.GetVariationCopy(useVars[m_Rand.Rand() % useVars.size()], m_Rand.Frand<T>(T(0.001), 1)));
xform->AddVariation(m_VariationList->GetVariationCopy(useVars[m_Rand.Rand() % useVars.size()], m_Rand.Frand<T>(T(0.001), 1)));
}
}
}
@ -1345,6 +1345,6 @@ private:
unique_ptr<Renderer<T, bucketT>> m_Renderer;
QTIsaac<ISAAC_SIZE, ISAAC_INT> m_Rand;
PaletteList<T> m_PaletteList;
VariationList<T>& m_VariationList;
shared_ptr<VariationList<T>> m_VariationList;
};
}

View File

@ -193,13 +193,16 @@ private:
/// member variables cannot be exported across module boundaries.
/// Derived classes should inherit from this using the CRTP, and declare a friend to it.
/// They also should make their constructors private and destructors public.
/// This has a severe flaw in that it cannot be used across module boundaries, else
/// every module will have its own copy. This makes it function as a per-module
/// singleton, which is unlikely to ever be desired.
/// Attribution: This class is a combination of
/// http://btorpey.github.io/blog/2014/02/12/shared-singletons/
/// and
/// http://enki-tech.blogspot.com/2012/08/c11-generic-singleton.html
/// </summary>
template <class T>
class Singleton
class EMBER_API Singleton
{
public:
/// <summary>
@ -243,6 +246,28 @@ public:
x(const x& other) = delete; \
const x& operator=(const x& other) = delete
//Use this if not deriving from the Singleton class and are declaring Instance() in a header and implementing it in a cpp file.
#define SINGLETON_INSTANCE_DECL(x) \
static std::shared_ptr<x> Instance(); \
x(const x& other) = delete; \
const x& operator=(const x& other) = delete//Semicolon deliberately omitted to force it on the caller.
//Use this if not deriving from the Singleton class and are implementing Instance() in a cpp file.
#define SINGLETON_INSTANCE_IMPL(x) \
std::shared_ptr<x> x::Instance() \
{ \
static weak_ptr<x> staticInstance; \
auto temp = staticInstance.lock(); \
\
if (!temp) \
{ \
temp.reset(new x()); \
staticInstance = temp; \
} \
\
return temp; \
}
/// <summary>
/// Open a file in binary mode and read its entire contents into a vector of bytes. Optionally null terminate.
/// </summary>

View File

@ -13,7 +13,7 @@ namespace EmberNs
/// This class is a singleton since all of its data is shared and read-only.
/// </summary>
template <typename T>
class EMBER_API VarFuncs : public Singleton<VarFuncs<T>>
class EMBER_API VarFuncs
{
public:
/// <summary>
@ -542,7 +542,7 @@ public:
}
}
SINGLETON_DERIVED_IMPL(VarFuncs<T>);
SINGLETON_INSTANCE_DECL(VarFuncs);//Implemented in VariationList.cpp
private:
/// <summary>

View File

@ -17,14 +17,12 @@ namespace EmberNs
m_Variations.push_back(new Post##varName##Variation<T>());
/// <summary>
/// Singleton pattern, return a reference to the only instance of this object in existence.
/// Singleton patterns, return a reference to the only instance of this object in existence.
/// </summary>
template <typename T>
VariationList<T>& VariationList<T>::Instance()
{
static VariationList<T> v;
return v;
}
SINGLETON_INSTANCE_IMPL(VarFuncs<T>)
template <typename T>
SINGLETON_INSTANCE_IMPL(VariationList<T>)
/// <summary>
/// Constructor which initializes all of the variation objects and stores them in the list.

View File

@ -21,10 +21,7 @@ template <typename T>
class EMBER_API VariationList
{
public:
static VariationList<T>& Instance();
~VariationList();
VariationList<T>(const VariationList<T>& varList) = delete;
VariationList<T>& operator = (const VariationList<T>& varList) = delete;
const Variation<T>* GetVariation(size_t index) const;
const Variation<T>* GetVariation(size_t index, eVariationType varType) const;
Variation<T>* GetVariationCopy(size_t index, T weight = 1) const;
@ -48,6 +45,8 @@ public:
const vector<Variation<T>*>& PreVars() const;
const vector<Variation<T>*>& PostVars() const;
SINGLETON_INSTANCE_DECL(VariationList);//Implemented in VariationList.cpp
private:
VariationList();
Variation<T>* MakeCopyWithWeight(const Variation<T>* var, T weight) const;

View File

@ -281,7 +281,6 @@ protected:
m_Params.push_back(ParamWithName<T>(&m_Scale, prefix + "hexes_scale", 1));
m_Params.push_back(ParamWithName<T>(true, &m_RotSin, prefix + "hexes_rotsin"));//Precalc.
m_Params.push_back(ParamWithName<T>(true, &m_RotCos, prefix + "hexes_rotcos"));
m_VarFuncs = VarFuncs<T>::Instance();
}
private:
@ -291,7 +290,7 @@ private:
T m_Scale;
T m_RotSin;//Precalc.
T m_RotCos;
std::shared_ptr<VarFuncs<T>> m_VarFuncs;
shared_ptr<VarFuncs<T>> m_VarFuncs = VarFuncs<T>::Instance();
};
/// <summary>
@ -3774,7 +3773,7 @@ public:
//No possible solution was found, so it is unused here.
//The full calculation is recomputed for every point.
return
"static void Position(__global real_t* p, __global real3* grad, int x, int y, real_t z, real_t s, real_t d, real2* v)\n"
"static void Position(__global real_t* p, __global real_t* grad, int x, int y, real_t z, real_t s, real_t d, real2* v)\n"
"{\n"
" real3 e, f;\n"
" e.x = x * 2.5;\n"
@ -3823,7 +3822,7 @@ public:
<< "\t\t{\n"
<< "\t\t for (dj = -1; dj < 2; dj++)\n"
<< "\t\t {\n"
<< "\t\t Position(globalShared + NOISE_INDEX, (__global real3*)(globalShared + NOISE_POINTS), cv.x + di, cv.y + dj, " << z << ", " << halfCellSize << ", " << distort << ", &p[i]);\n"
<< "\t\t Position(globalShared + NOISE_INDEX, globalShared + NOISE_POINTS, cv.x + di, cv.y + dj, " << z << ", " << halfCellSize << ", " << distort << ", &p[i]);\n"
<< "\t\t i++;\n"
<< "\t\t }\n"
<< "\t\t}\n"
@ -3839,7 +3838,7 @@ public:
<< "\t\t{\n"
<< "\t\t for (dj = -1; dj < 2; dj++)\n"
<< "\t\t {\n"
<< "\t\t Position(globalShared + NOISE_INDEX, (__global real3*)(globalShared + NOISE_POINTS), cv.x + di, cv.y + dj, " << z << ", " << halfCellSize << ", " << distort << ", &p[i]);\n"
<< "\t\t Position(globalShared + NOISE_INDEX, globalShared + NOISE_POINTS, cv.x + di, cv.y + dj, " << z << ", " << halfCellSize << ", " << distort << ", &p[i]);\n"
<< "\t\t i++;\n"
<< "\t\t }\n"
<< "\t\t}\n"
@ -3870,7 +3869,6 @@ protected:
void Init()
{
string prefix = Prefix();
m_VarFuncs = VarFuncs<T>::Instance();
m_Params.clear();
m_Params.reserve(8);
m_Params.push_back(ParamWithName<T>(&m_CellSize, prefix + "crackle_cellsize", 1));
@ -3912,7 +3910,7 @@ private:
T m_Z;
T m_HalfCellSize;//Precalc
v2T m_C[CACHE_WIDTH][CACHE_WIDTH];//Not kept as a precalc because it crashes Nvidia GPUs.
std::shared_ptr<VarFuncs<T>> m_VarFuncs;
shared_ptr<VarFuncs<T>> m_VarFuncs = VarFuncs<T>::Instance();
};
/// <summary>

View File

@ -1314,6 +1314,7 @@ public:
<< "\t\t break; \n"
<< "\n"
<< "\t\t case " << SHAPE_BLUR << ": \n"
<< "\t\t default: \n"
<< "\t\t r = (1 + " << edge << ") * MwcNext01(mwc); \n"
<< "\n"
<< "\t\t if (r > 1 - " << edge << ")\n"
@ -1369,6 +1370,7 @@ public:
<< "\t\t break; \n"
<< "\n"
<< "\t\t case " << MAP_BUBBLE2 << ": \n"
<< "\t\t default: \n"
<< "\t\t r = 0.25 - (SQR(vx) + SQR(vy)); \n"
<< "\n"
<< "\t\t if (r < 0)\n"
@ -1382,13 +1384,13 @@ public:
<< "\t\t break; \n"
<< "\t\t }\n"
<< "\n"
<< "\t\t p = PerlinNoise3D(&v, globalShared + NOISE_INDEX, (__global real3*)(globalShared + NOISE_POINTS), " << amps << ", " << freqs << ", iOctaves); \n"
<< "\t\t p = PerlinNoise3D(&v, globalShared + NOISE_INDEX, globalShared + NOISE_POINTS, " << amps << ", " << freqs << ", iOctaves); \n"
<< "\n"
<< "\t\t if (p > 0)\n"
<< "\t\t e = p * (1 + e * e * 20) + 2 * e; \n"
<< "\t\t else\n"
<< "\t\t e = p * (1 + e * e * 20) - 2 * e; \n"
<< "}\n"
<< "\t\t}\n"
<< "\t\twhile ((e < " << notchBottom << " || e > " << notchTop << ") && t++ < iBailout); \n"
<< "\n"
<< "\t\tvOut.x = xform->m_VariationWeights[" << varIndex << "] * vx; \n"
@ -1413,7 +1415,6 @@ protected:
void Init()
{
string prefix = Prefix();
m_VarFuncs = VarFuncs<T>::Instance();
m_Params.clear();
m_Params.reserve(15);
m_Params.push_back(ParamWithName<T>(&m_Shape, prefix + "dc_perlin_shape", 0, eParamType::INTEGER, 0, 2));//Params.
@ -1448,7 +1449,7 @@ private:
T m_SelectBailout;
T m_NotchBottom;//Precalc.
T m_NotchTop;
shared_ptr<VarFuncs<T>> m_VarFuncs;
shared_ptr<VarFuncs<T>> m_VarFuncs = VarFuncs<T>::Instance();
};
MAKEPREPOSTPARVAR(DCBubble, dc_bubble, DC_BUBBLE)

View File

@ -879,7 +879,7 @@ public:
bool Flatten(vector<string>& names)
{
bool shouldFlatten = true;
VariationList<T>& vl(VariationList<T>::Instance());
auto vl = VariationList<T>::Instance();
if (GetVariationById(eVariationId::VAR_FLATTEN) == nullptr)
{
@ -898,7 +898,7 @@ public:
}
//Now traverse the parameters for this variation.
if (ParametricVariation<T>* parVar = dynamic_cast<ParametricVariation<T>*>(var))//If any parametric variation parameter is present and non-zero, don't flatten.
if (auto parVar = dynamic_cast<ParametricVariation<T>*>(var))//If any parametric variation parameter is present and non-zero, don't flatten.
{
for (auto& s : names)
{
@ -915,7 +915,7 @@ public:
if (shouldFlatten)//Flatten was not present and neither was any variation name or parameter in the list.
{
auto var = vl.GetVariationCopy(eVariationId::VAR_FLATTEN);
auto var = vl->GetVariationCopy(eVariationId::VAR_FLATTEN);
if (AddVariation(var))
{

View File

@ -337,8 +337,8 @@ public:
ScanForEmberNodes(rootnode, bn, embers, useDefaults);
xmlFreeDoc(doc);
emberSize = embers.size();
auto b = embers.begin();
auto secondToLast = Advance(embers.begin(), emberSize - 2);
auto first = embers.begin();
//t.Toc("ScanForEmberNodes");
//Check to see if the first control point or the second-to-last
@ -346,11 +346,16 @@ public:
//and should be reset to linear (with a warning).
if (emberSize > 0)
{
if (b->m_Interp == eInterp::EMBER_INTERP_SMOOTH)
b->m_Interp = eInterp::EMBER_INTERP_LINEAR;
if (first->m_Interp == eInterp::EMBER_INTERP_SMOOTH)
first->m_Interp = eInterp::EMBER_INTERP_LINEAR;
if (emberSize >= 2 && secondToLast->m_Interp == eInterp::EMBER_INTERP_SMOOTH)
secondToLast->m_Interp = eInterp::EMBER_INTERP_LINEAR;
if (emberSize >= 2)
{
auto secondToLast = Advance(embers.begin(), emberSize - 2);
if (secondToLast->m_Interp == eInterp::EMBER_INTERP_SMOOTH)
secondToLast->m_Interp = eInterp::EMBER_INTERP_LINEAR;
}
}
//Finally, ensure that consecutive 'rotate' parameters never exceed
@ -1263,7 +1268,7 @@ private:
//Only correct names if it came from an outside source. Names originating from this library are always considered correct.
string s = fromEmber ? string(CCX(curAtt->name)) : GetCorrectedVariationName(m_BadVariationNames, curAtt);
if (auto var = m_VariationList.GetVariation(s))
if (auto var = m_VariationList->GetVariation(s))
{
T weight = 0;
Aton(attStr, weight);
@ -1543,7 +1548,7 @@ private:
static bool m_Init;
static unordered_map<string, string> m_BadParamNames;
static vector<pair<pair<string, string>, vector<string>>> m_BadVariationNames;
VariationList<T>& m_VariationList;//The variation list used to make copies of variations to populate the embers with.
shared_ptr<VariationList<T>> m_VariationList;//The variation list used to make copies of variations to populate the embers with.
PaletteList<T> m_PaletteList;
};
}