--User changes

-Remove the option --intpalette to format the palette in the xml as ints. If they are not hex formatted, then they should always be float. This option was pointless.
 -Cleanup some options text for the command line programs.
 -Allow for dragging around flames in the library tab. This is useful for setting up the order of an animation.
 -Make the opening of large files in Fractorium much more efficient when not-appending.
 -Make the opening of large files in all EmberRender and EmberAnimate more efficient.
 -Better error reporting when opening files.

--Bug fixes
 -Get rid of leftover artifacts that would appear on preview thumbnails when either switching SP/DP or re-rendering previews.
 -Filename extension was not being appended on Linux when saving as Xml, thus making it impossible to drag that file back in becase drop is filtered on extension.

--Code changes
 -Move GCC compiler spec to C++14. Building with 5.3 now on linux.
 -Use inline member data initializers.
 -Make a #define for static for use in Utils.h to make things a little cleaner.
 -Make various functions able to take arbitrary collections as their parameters rather than just vectors.
 -Make library collection a list rather than vector. This alleviates the need to re-sync pointers whenever the collection changes.
 -Subclass QTreeWidget for the library tree. Two new files added for this.
 -Remove all usage of #ifdef ROW_ONLY_DE in DEOpenCLKernelCreator, it was never used.
 -Add move constructor and assignment operator to EmberFile.
 -Add the ability to use a pointer to outside memory in the renderer for the vector of Ember<T>.
 -Make a lot more functions const where they should be.
This commit is contained in:
mfeemster
2016-04-03 18:55:12 -07:00
parent 124f807772
commit b690bf8071
64 changed files with 890 additions and 1048 deletions

View File

@ -25,9 +25,7 @@ public:
/// <summary>
/// Empty constructor. This class should never be used unless it's been properly constructed with the constructor that takes arguments.
/// </summary>
CarToRas()
{
}
CarToRas() = default;
/// <summary>
/// Constructor that takes arguments to set up the bounds and passes them to Init().

View File

@ -44,9 +44,12 @@ public:
/// Default constructor which calls Init() to set default values.
/// </summary>
Ember()
: m_VariationList(VariationList<T>::Instance())
{
Init();
m_Background.Reset();
m_Curves.Init();
m_Xforms.reserve(12);
m_CamMat = m3T(0);
m_ProjFunc = &EmberNs::Ember<T>::ProjectNone;
}
/// <summary>
@ -54,8 +57,6 @@ public:
/// </summary>
/// <param name="ember">The Ember object to copy</param>
Ember(const Ember<T>& ember)
: m_Edits(nullptr),
m_VariationList(VariationList<T>::Instance())
{
Ember<T>::operator=<T>(ember);
}
@ -66,8 +67,6 @@ public:
/// <param name="ember">The Ember object to copy</param>
template <typename U>
Ember(const Ember<U>& ember)
: m_Edits(nullptr),
m_VariationList(VariationList<T>::Instance())
{
Ember<T>::operator=<U>(ember);
}
@ -178,74 +177,10 @@ public:
if (ember.m_Edits)
m_Edits = xmlCopyDoc(ember.m_Edits, 1);
CopyVec(m_EmberMotionElements, ember.m_EmberMotionElements);
CopyCont(m_EmberMotionElements, ember.m_EmberMotionElements);
return *this;
}
/// <summary>
/// Set common default values.
/// </summary>
void Init()
{
m_FinalRasW = 1920;
m_FinalRasH = 1080;
m_OrigFinalRasW = 1920;
m_OrigFinalRasH = 1080;
m_OrigPixPerUnit = 240;
m_SubBatchSize = DEFAULT_SBS;
m_FuseCount = 15;
m_Supersample = 1;
m_TemporalSamples = 100;
m_Symmetry = 0;
m_Quality = 100;
m_PixelsPerUnit = 240;
m_Zoom = 0;
m_ProjFunc = &EmberNs::Ember<T>::ProjectNone;
m_CamZPos = 0;
m_CamPerspective = 0;
m_CamYaw = 0;
m_CamPitch = 0;
m_CamDepthBlur = 0;
m_BlurCoef = 0;
m_CamMat = m3T(0);
m_CenterX = 0;
m_CenterY = 0;
m_RotCenterY = 0;
m_Rotate = 0;
m_Brightness = 4;
m_Gamma = 4;
m_Vibrancy = 1;
m_GammaThresh = T(0.01);
m_HighlightPower = -1;
m_Time = 0;
m_Background.Reset();
m_Interp = eInterp::EMBER_INTERP_SMOOTH;
m_AffineInterp = eAffineInterp::AFFINE_INTERP_LOG;
//DE filter.
m_MinRadDE = 0;
m_MaxRadDE = 9;
m_CurveDE = T(0.4);
//Spatial filter.
m_SpatialFilterType = eSpatialFilterType::GAUSSIAN_SPATIAL_FILTER;
m_SpatialFilterRadius = T(0.5);
//Temporal filter.
m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER;
m_TemporalFilterExp = 0;
m_TemporalFilterWidth = 1;
//Palette.
m_PaletteMode = ePaletteMode::PALETTE_LINEAR;
m_PaletteInterp = ePaletteInterp::INTERP_HSV;
//Curves.
m_Curves.Init();
m_Name = "No name";
m_ParentFilename = "No parent";
//Internal values.
m_Index = 0;
m_ScaleType = eScaleType::SCALE_NONE;
m_Xforms.reserve(12);
m_Edits = nullptr;
}
/// <summary>
/// Add a copy of a new xform to the xforms vector.
/// </summary>
@ -286,7 +221,7 @@ public:
/// <param name="xformPad">The total number of xforms if additional padding xforms are desired. Default: 0.</param>
/// <param name="doFinal">Whether to copy the final xform. Default: false.</param>
/// <returns>The newly constructed ember</returns>
Ember<T> Copy(size_t xformPad = 0, bool doFinal = false)
Ember<T> Copy(size_t xformPad = 0, bool doFinal = false) const
{
Ember<T> ember(*this);
ember.PadXforms(xformPad);
@ -443,7 +378,7 @@ public:
/// </summary>
/// <param name="xform">A pointer to the xform to test</param>
/// <returns>True if matched, else false.</returns>
bool IsFinalXform(Xform<T>* xform)
bool IsFinalXform(Xform<T>* xform) const
{
return &m_FinalXform == xform;
}
@ -695,7 +630,7 @@ public:
/// <param name="embers">Vector of embers</param>
/// <param name="coefs">Coefficients vector which must be the same length as the vector of embers</param>
/// <param name="stagger">Stagger if greater than 0</param>
void Interpolate(vector<Ember<T>>& embers, vector<T>& coefs, T stagger)
void Interpolate(const vector<Ember<T>>& embers, vector<T>& coefs, T stagger)
{
Interpolate(embers.data(), embers.size(), coefs, stagger);
}
@ -708,7 +643,7 @@ public:
/// <param name="size">Number of elements in the buffer of embers</param>
/// <param name="coefs">Coefficients vector which must be the same length as the vector of embers</param>
/// <param name="stagger">Stagger if greater than 0</param>
void Interpolate(Ember<T>* embers, size_t size, vector<T>& coefs, T stagger)
void Interpolate(const Ember<T>* embers, size_t size, vector<T>& coefs, T stagger)
{
if (size != coefs.size() || size < 2)
return;
@ -996,7 +931,7 @@ public:
/// </summary>
/// <param name="embers">Vector of embers</param>
/// <param name="t">Used in calculating Catmull-Rom coefficients</param>
void InterpolateCatmullRom(vector<Ember<T>>& embers, T t)
void InterpolateCatmullRom(const vector<Ember<T>>& embers, T t)
{
InterpolateCatmullRom(embers.data(), embers.size(), t);
}
@ -1008,7 +943,7 @@ public:
/// <param name="embers">Pointer to buffer of embers</param>
/// <param name="size">Number of elements in the buffer of embers</param>
/// <param name="t">Used in calculating Catmull-Rom coefficients</param>
void InterpolateCatmullRom(Ember<T>* embers, size_t size, T t)
void InterpolateCatmullRom(const Ember<T>* embers, size_t size, T t)
{
T t2 = t * t;
T t3 = t2 * t;
@ -1537,50 +1472,50 @@ public:
//The width and height in pixels of the final output image. The size of the histogram and DE filtering buffers will differ from this.
//Xml fields: "size".
size_t m_FinalRasW;
size_t m_FinalRasH;
size_t m_OrigFinalRasW;//Keep track of the originals read from the Xml, because...
size_t m_OrigFinalRasH;//the dimension may change in an editor and the originals are needed for the aspect ratio.
T m_OrigPixPerUnit;
size_t m_FinalRasW = 1920;
size_t m_FinalRasH = 1080;
size_t m_OrigFinalRasW = 1920;//Keep track of the originals read from the Xml, because...
size_t m_OrigFinalRasH = 1080;//the dimension may change in an editor and the originals are needed for the aspect ratio.
T m_OrigPixPerUnit = 240;
//The iteration depth. This was a rendering parameter in flam3 but has been made a member here
//so that it can be adjusted more easily.
size_t m_SubBatchSize;
size_t m_SubBatchSize = DEFAULT_SBS;
//The number of iterations to disregard for each sub batch. This was a rendering parameter in flam3 but has been made a member here
//so that it can be adjusted more easily.
size_t m_FuseCount;
size_t m_FuseCount = 15;
//The multiplier in size of the histogram and DE filtering buffers. Must be at least one, preferrably never larger than 4, only useful at 2.
//Xml field: "supersample" or "overample (deprecated)".
size_t m_Supersample;
size_t m_Supersample = 1;
//When animating, split each pass into this many pieces, each doing a fraction of the total iterations. Each temporal sample
//will render an interpolated instance of the ember that is a fraction of the current ember and the next one.
//When rendering a single image, this field is always set to 1.
//Xml field: "temporal_samples".
size_t m_TemporalSamples;
size_t m_TemporalSamples = 100;
//Whether or not any symmetry was added. This field is in a bit of a state of conflict right now as flam3 has a severe bug.
//Xml field: "symmetry".
intmax_t m_Symmetry;
intmax_t m_Symmetry = 0;
//The number of iterations per pixel of the final output image. Note this is not affected by the increase in pixels in the
//histogram and DE filtering buffer due to supersampling. It can be affected by a non-zero zoom value though.
//10 is a good value for interactive/real-time rendering, 100-200 is good for previewing, 1000 is good for final output. Above that is mostly a waste of energy.
//Xml field: "quality".
T m_Quality;
T m_Quality = 100;
//The number of pixels in the final output image that corresponds to the distance from 0-1 in the cartesian plane used for iterating.
//A larger value produces a more zoomed in imgage. A value of 240 is commonly used, but in practice it varies widely depending on the image.
//Note that increasing this value does not adjust the quality by a proportional amount, so an increased value may produce a degraded image.
//Xml field: "scale".
T m_PixelsPerUnit;
T m_PixelsPerUnit = 240;
//A value greater than 0 will zoom in the field of view, however it will also increase the quality by a proportional amount. This is used to
//overcome the shortcoming of scale by also adjusting the quality.
//Xml field: "zoom".
T m_Zoom;
T m_Zoom = 0;
//3D fields.
private:
@ -1589,22 +1524,22 @@ private:
public:
//Xml field: "cam_zpos".
T m_CamZPos;
T m_CamZPos = 0;
//Xml field: "cam_persp".
T m_CamPerspective;
T m_CamPerspective = 0;
//Xml field: "cam_yaw".
T m_CamYaw;
T m_CamYaw = 0;
//Xml field: "cam_pitch".
T m_CamPitch;
T m_CamPitch = 0;
//Xml field: "cam_dof".
T m_CamDepthBlur;
T m_CamDepthBlur = 0;
private:
T m_BlurCoef;
T m_BlurCoef = 0;
public:
m3T m_CamMat;
@ -1612,38 +1547,38 @@ public:
//The camera offset from the center of the cartesian plane. Since this is the camera offset, the final output image will be moved in the opposite
//direction of the values specified. There is also a second copy of the Y coordinate needed because m_CenterY will be modified during strips rendering.
//Xml field: "center".
T m_CenterX;
T m_CenterY;
T m_RotCenterY;
T m_CenterX = 0;
T m_CenterY = 0;
T m_RotCenterY = 0;
//Rotate the camera by this many degrees. Since this is a camera rotation, the final output image will be rotated counter-clockwise.
//Xml field: "rotate".
T m_Rotate;
T m_Rotate = 0;
//Determine how bright to make the image during final accumulation.
//Xml field: "brightness".
T m_Brightness;
T m_Brightness = 4;
//Gamma level used in gamma correction during final accumulation.
//Xml field: "gamma".
T m_Gamma;
T m_Gamma = 4;
//Used in color correction during final accumulation.
//Xml field: "vibrancy".
T m_Vibrancy;
T m_Vibrancy = 1;
//Gamma threshold used in gamma correction during final accumulation.
//Xml field: "gamma_threshold".
T m_GammaThresh;
T m_GammaThresh = T(0.01);
//Value to control saturation of some pixels in gamma correction during final accumulation.
//Xml field: "highlight_power".
T m_HighlightPower;
T m_HighlightPower = -1;
//When animating a file full of many embers, this value is used to specify the time in the animation
//that this ember should be rendered. They must all be sequential and increase by a default value of 1.
//Xml field: "time".
T m_Time;
T m_Time = 0;
//The background color of the image used in final accumulation, ranged 0-1.
//Xml field: "background".
@ -1653,66 +1588,66 @@ public:
//The type of interpolation to use when interpolating between embers for animation.
//Xml field: "interpolation".
eInterp m_Interp;
eInterp m_Interp = eInterp::EMBER_INTERP_SMOOTH;
//The type of interpolation to use on affine transforms when interpolating embers for animation.
//Xml field: "interpolation_type" or "interpolation_space (deprecated)".
eAffineInterp m_AffineInterp;
eAffineInterp m_AffineInterp = eAffineInterp::AFFINE_INTERP_LOG;
//The type of interpolation to use for the palette when interpolating embers for animation.
//Xml field: "palette_interpolation".
ePaletteInterp m_PaletteInterp;
ePaletteInterp m_PaletteInterp = ePaletteInterp::INTERP_HSV;
//Temporal Filter.
//Only used if temporal filter type is exp, else unused.
//Xml field: "temporal_filter_exp".
T m_TemporalFilterExp;
T m_TemporalFilterExp = 0;
//The width of the temporal filter.
//Xml field: "temporal_filter_width".
T m_TemporalFilterWidth;
T m_TemporalFilterWidth = 1;
//The type of the temporal filter: Gaussian, Box or Exp.
//Xml field: "temporal_filter_type".
eTemporalFilterType m_TemporalFilterType;
eTemporalFilterType m_TemporalFilterType = eTemporalFilterType::BOX_TEMPORAL_FILTER;
//Density Estimation Filter.
//The minimum radius of the DE filter.
//Xml field: "estimator_minimum".
T m_MinRadDE;
T m_MinRadDE = 0;
//The maximum radius of the DE filter.
//Xml field: "estimator_radius".
T m_MaxRadDE;
T m_MaxRadDE = 9;
//The shape of the curve that governs how quickly or slowly the filter drops off as it moves away from the center point.
//Xml field: "estimator_curve".
T m_CurveDE;
T m_CurveDE = T(0.4);
//Spatial Filter.
//The radius of the spatial filter used in final accumulation.
//Xml field: "filter".
T m_SpatialFilterRadius;
T m_SpatialFilterRadius = T(0.5);
//The type of spatial filter used in final accumulation:
//Gaussian, Hermite, Box, Triangle, Bell, Bspline, Lanczos3
//Lanczos2, Mitchell, Blackman, Catrom, Hamming, Hanning, Quadratic.
//Xml field: "filter_shape".
eSpatialFilterType m_SpatialFilterType;
eSpatialFilterType m_SpatialFilterType = eSpatialFilterType::GAUSSIAN_SPATIAL_FILTER;
//Palette.
//The method used for retrieving a color from the palette when accumulating to the histogram: step, linear.
//Xml field: "palette_mode".
ePaletteMode m_PaletteMode;
ePaletteMode m_PaletteMode = ePaletteMode::PALETTE_LINEAR;
//The color palette to use. Can be specified inline as Xml color fields, or as a hex buffer. Can also be specified
//as an index into the palette file with an optional hue rotation applied. Inserting as a hex buffer is the preferred method.
//Xml field: "color" or "colors" or "palette" .
Palette<T> m_Palette;
Palette<T> m_Palette;//Final palette that is actually used is a copy of this inside of render, which will be of type bucketT (float).
//Curves used to adjust the color during final accumulation.
Curves<T> m_Curves;
@ -1721,18 +1656,18 @@ public:
//The name of this ember.
//Xml field: "name".
string m_Name;
string m_Name = string("No name");
//The name of the file that this ember was contained in.
//Xml field: "".
string m_ParentFilename;
string m_ParentFilename = string("No parent");
//An Xml edit document describing information about the author as well as an edit history of the ember.
//Xml field: "edit".
xmlDocPtr m_Edits;
xmlDocPtr m_Edits = nullptr;
//The 0-based position of this ember in the file it was contained in.
size_t m_Index;
size_t m_Index = 0;
//The list of motion elements for the top-level flame params
vector<EmberMotion<T>> m_EmberMotionElements;
@ -1741,7 +1676,7 @@ private:
/// <summary>
/// The type of scaling used when resizing.
/// </summary>
eScaleType m_ScaleType;
eScaleType m_ScaleType = eScaleType::SCALE_NONE;
//The vector containing all of the xforms.
//Xml field: "xform".
@ -1753,7 +1688,7 @@ private:
Xform<T> m_FinalXform;
//Single global reference to create variations with.
VariationList<T>& m_VariationList;
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.
@ -1763,7 +1698,7 @@ private:
/// <param name="coefs">The list of coefficients to interpolate</param>
/// <param name="size">The size of the lists, both must match.</param>
template <T Ember<T>::*m>
void InterpT(Ember<T>* embers, vector<T>& coefs, size_t size)
void InterpT(const Ember<T>* embers, const vector<T>& coefs, size_t size)
{
this->*m = 0;
@ -1778,7 +1713,7 @@ private:
/// <param name="coefs">The list of coefficients to interpolate</param>
/// <param name="size">The size of the lists, both must match.</param>
template <typename M, M Ember<T>::*m>
void InterpX(Ember<T>* embers, vector<T>& coefs, size_t size)
void InterpX(const Ember<T>* embers, const vector<T>& coefs, size_t size)
{
this->*m = M();
@ -1793,7 +1728,7 @@ private:
/// <param name="coefs">The list of coefficients to interpolate</param>
/// <param name="size">The size of the lists, both must match.</param>
template <size_t Ember<T>::*m>
void InterpI(Ember<T>* embers, vector<T>& coefs, size_t size)
void InterpI(const Ember<T>* embers, const vector<T>& coefs, size_t size)
{
T t = 0;
@ -1813,7 +1748,7 @@ private:
/// <param name="coefs">The list of coefficients to interpolate</param>
/// <param name="size">The size of the lists, both must match.</param>
template <T Xform<T>::*m>
void InterpXform(Xform<T>* xform, size_t i, Ember<T>* embers, vector<T>& coefs, size_t size)
void InterpXform(Xform<T>* xform, size_t i, const Ember<T>* embers, const vector<T>& coefs, size_t size)
{
xform->*m = T(0);

View File

@ -94,8 +94,10 @@ static inline size_t NowMs()
//These two must always match.
#ifdef _WIN32
#define ALIGN __declspec(align(16))
#define STATIC static
#else
#define ALIGN __attribute__ ((aligned (16)))
#define STATIC
#endif
#define ALIGN_CL "((aligned (16)))"//The extra parens are necessary.

View File

@ -17,9 +17,7 @@ public:
/// <summary>
/// Default constructor, which calls the base, which sets first and second to their defaults.
/// </summary>
MotionParam()
{
}
MotionParam() = default;
/// <summary>
/// Member-wise constructor.
@ -90,12 +88,8 @@ public:
/// <summary>
/// Default constructor to initialize motion freq and offset to 0 and the motion func to SIN.
/// </summary>
EmberMotion()
{
m_MotionFreq = 0;
m_MotionFunc = eMotion::MOTION_SIN;
m_MotionOffset = 0;
}
EmberMotion() = default;
~EmberMotion() = default;
/// <summary>
/// Default copy constructor.
@ -136,16 +130,16 @@ public:
template <typename U>
EmberMotion& operator = (const EmberMotion<U>& other)
{
CopyVec(m_MotionParams, other.m_MotionParams);
CopyCont(m_MotionParams, other.m_MotionParams);
m_MotionFunc = other.m_MotionFunc;
m_MotionFreq = T(other.m_MotionFreq);
m_MotionOffset = T(other.m_MotionOffset);
return *this;
}
T m_MotionFreq;
T m_MotionOffset;
eMotion m_MotionFunc;
T m_MotionFreq = 0;
T m_MotionOffset = 0;
eMotion m_MotionFunc = eMotion::MOTION_SIN;
vector<MotionParam<T>> m_MotionParams;
};
}

View File

@ -40,6 +40,7 @@
#include <iostream>
#include <iomanip>
#include <limits>
#include <list>
#ifdef __APPLE__
#include <malloc/malloc.h>
#else

View File

@ -23,9 +23,9 @@ public:
/// <summary>
/// Empty constructor.
/// </summary>
EmberToXml()
{
}
EmberToXml() = default;
~EmberToXml() = default;
EmberToXml(const EmberToXml<T>& e) = delete;
/// <summary>
/// Save the ember to the specified file.
@ -34,33 +34,32 @@ public:
/// <param name="ember">The ember to save</param>
/// <param name="printEditDepth">How deep the edit depth goes</param>
/// <param name="doEdits">If true included edit tags, else don't.</param>
/// <param name="intPalette">If true use integers instead of floating point numbers when embedding a non-hex formatted palette, else use floating point numbers.</param>
/// <param name="hexPalette">If true, embed a hexadecimal palette instead of Xml Color tags, else use Xml color tags.</param>
/// <param name="append">If true, append to the file if it already exists, else create a new file.</param>
/// <param name="start">Whether a new file is to be started</param>
/// <param name="finish">Whether an existing file is to be ended</param>
/// <returns>True if successful, else false</returns>
bool Save(const string& filename, Ember<T>& ember, size_t printEditDepth, bool doEdits, bool intPalette, bool hexPalette, bool append = false, bool start = false, bool finish = false)
bool Save(const string& filename, Ember<T>& ember, size_t printEditDepth, bool doEdits, bool hexPalette, bool append = false, bool start = false, bool finish = false)
{
vector<Ember<T>> vec;
vec.push_back(ember);
return Save(filename, vec, printEditDepth, doEdits, intPalette, hexPalette, append, start, finish);
return Save(filename, vec, printEditDepth, doEdits, hexPalette, append, start, finish);
}
/// <summary>
/// Save a vector of embers to the specified file.
/// Save a container of embers to the specified file.
/// </summary>
/// <param name="filename">Full path and filename</param>
/// <param name="embers">The vector of embers to save</param>
/// <param name="embers">The container of embers to save</param>
/// <param name="printEditDepth">How deep the edit depth goes</param>
/// <param name="doEdits">If true included edit tags, else don't.</param>
/// <param name="intPalette">If true use integers instead of floating point numbers when embedding a non-hex formatted palette, else use floating point numbers.</param>
/// <param name="hexPalette">If true, embed a hexadecimal palette instead of Xml Color tags, else use Xml color tags.</param>
/// <param name="append">If true, append to the file if it already exists, else create a new file.</param>
/// <param name="start">Whether a new file is to be started</param>
/// <param name="finish">Whether an existing file is to be ended</param>
/// <returns>True if successful, else false</returns>
bool Save(const string& filename, vector<Ember<T>>& embers, size_t printEditDepth, bool doEdits, bool intPalette, bool hexPalette, bool append = false, bool start = false, bool finish = false)
template <typename Alloc, template <typename, typename> class C>
bool Save(const string& filename, C<Ember<T>, Alloc>& embers, size_t printEditDepth, bool doEdits, bool hexPalette, bool append = false, bool start = false, bool finish = false)
{
bool b = false;
bool hasTimes = false;
@ -77,15 +76,19 @@ public:
if (f.is_open())
{
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 (size_t i = 1; i < embers.size(); i++)
for (auto it = Advance(embers.begin(), 1); it != embers.end(); ++it)
{
if (embers[i].m_Time != embers[i - 1].m_Time)
if (it->m_Time != prev->m_Time)
{
hasTimes = true;
break;
}
prev = it;
}
if (!hasTimes)
@ -101,7 +104,7 @@ public:
for (auto& ember : embers)
{
string s = ToString(ember, "", printEditDepth, doEdits, intPalette, hexPalette);
string s = ToString(ember, "", printEditDepth, doEdits, hexPalette);
f.write(s.c_str(), s.size());
}
@ -144,10 +147,9 @@ public:
/// <param name="extraAttributes">If true, add extra attributes, else don't</param>
/// <param name="printEditDepth">How deep the edit depth goes</param>
/// <param name="doEdits">If true included edit tags, else don't.</param>
/// <param name="intPalette">If true use integers instead of floating point numbers when embedding a non-hex formatted palette, else use floating point numbers.</param>
/// <param name="hexPalette">If true, embed a hexadecimal palette instead of Xml Color tags, else use Xml color tags.</param>
/// <returns>The Xml string representation of the passed in ember</returns>
string ToString(Ember<T>& ember, const string& extraAttributes, size_t printEditDepth, bool doEdits, bool intPalette, bool hexPalette = true)
string ToString(Ember<T>& ember, const string& extraAttributes, size_t printEditDepth, bool doEdits, bool hexPalette = true)
{
size_t i, j;
string s;
@ -292,19 +294,9 @@ public:
//The original used a precision of 6 which is totally unnecessary, use 2.
if (IsClose(a, 255.0))
{
if (intPalette)
os << "<color index=\"" << i << "\" rgb=\"" << int(std::rint(r)) << " " << int(std::rint(g)) << " " << int(std::rint(b)) << "\"/>";
else
os << "<color index=\"" << i << "\" rgb=\"" << std::fixed << std::setprecision(2) << r << " " << g << " " << b << "\"/>";
}
os << "<color index=\"" << i << "\" rgb=\"" << std::fixed << std::setprecision(2) << r << " " << g << " " << b << "\"/>";
else
{
if (intPalette)
os << " <color index=\"" << i << "\" rgba=\"" << int(std::rint(r)) << " " << int(std::rint(g)) << " " << int(std::rint(b)) << " " << int(std::rint(a)) << "\"/>";
else
os << " <color index=\"" << i << "\" rgba=\"" << std::fixed << std::setprecision(2) << r << " " << g << " " << b << " " << a << "\"/>";
}
os << " <color index=\"" << i << "\" rgba=\"" << std::fixed << std::setprecision(2) << r << " " << g << " " << b << " " << a << "\"/>";
os << "\n";
}

View File

@ -38,7 +38,7 @@ public:
/// <param name="sourceEmbers">The array of embers to align</param>
/// <param name="destEmbers">The array which will contain the aligned embers </param>
/// <param name="count">The number of elements in sourceEmbers</param>
static void Align(Ember<T>* sourceEmbers, Ember<T>* destEmbers, size_t count)
static void Align(const Ember<T>* sourceEmbers, Ember<T>* destEmbers, size_t count)
{
bool aligned = true;
bool currentFinal, final = sourceEmbers[0].UseFinalXform();
@ -297,7 +297,7 @@ public:
/// </summary>
/// <param name="embers">The vector of embers to inspect for xaos</param>
/// <returns>True if at least one ember contained xaos, else false.</returns>
static bool AnyXaosPresent(vector<Ember<T>>& embers)
static bool AnyXaosPresent(const vector<Ember<T>>& embers)
{
return AnyXaosPresent(embers.data(), embers.size());
}
@ -308,7 +308,7 @@ public:
/// <param name="embers">The array of embers to inspect</param>
/// <param name="size">The size of the embers array</param>
/// <returns>True if at least one ember contained xaos, else false.</returns>
static bool AnyXaosPresent(Ember<T>* embers, size_t size)
static bool AnyXaosPresent(const Ember<T>* embers, size_t size)
{
for (size_t i = 0; i < size; i++)
if (embers[i].XaosPresent())
@ -333,7 +333,7 @@ public:
/// <param name="embers">The array of embers to inspect</param>
/// <param name="size">The size of the embers array</param>
/// <returns>The greatest non-final xform count in any of the embers</returns>
static size_t MaxXformCount(Ember<T>* embers, size_t size)
static size_t MaxXformCount(const Ember<T>* embers, size_t size)
{
size_t i, maxCount = 0;
@ -349,7 +349,7 @@ public:
/// </summary>
/// <param name="embers">The vector of embers to inspect the presence of a final xform</param>
/// <returns>True if any contained a non-empty final xform, else false.</returns>
static bool AnyFinalPresent(vector<Ember<T>>& embers)
static bool AnyFinalPresent(const vector<Ember<T>>& embers)
{
return AnyFinalPresent(embers.data(), embers.size());
}
@ -360,7 +360,7 @@ public:
/// <param name="embers">The array of embers to inspect the presence of a final xform</param>
/// <param name="size">The size of the embers array</param>
/// <returns>True if any contained a final xform, else false.</returns>
static bool AnyFinalPresent(Ember<T>* embers, size_t size)
static bool AnyFinalPresent(const Ember<T>* embers, size_t size)
{
for (size_t i = 0; i < size; i++)
if (embers[i].UseFinalXform())
@ -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(vector<Ember<T>>& embers, T time, T stagger, Ember<T>& result)
static 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(Ember<T>* embers, size_t size, T time, T stagger, Ember<T>& result)
static void Interpolate(const Ember<T>* embers, size_t size, T time, T stagger, Ember<T>& result)
{
if (size == 1)
{
@ -585,7 +585,7 @@ public:
/// <param name="cxAng">The vec2 vector to store the polar angular values</param>
/// <param name="cxMag">The vec2 vector to store the polar magnitude values</param>
/// <param name="cxTrn">The vec2 vector to store the polar translation values</param>
static void ConvertLinearToPolar(vector<Ember<T>>& embers, size_t xfi, size_t cflag, vector<v2T>& cxAng, vector<v2T>& cxMag, vector<v2T>& cxTrn)
static void ConvertLinearToPolar(const vector<Ember<T>>& embers, size_t xfi, size_t cflag, vector<v2T>& cxAng, vector<v2T>& cxMag, vector<v2T>& cxTrn)
{
ConvertLinearToPolar(embers.data(), embers.size(), xfi, cflag, cxAng, cxMag, cxTrn);
}
@ -601,7 +601,7 @@ public:
/// <param name="cxAng">The vec2 vector to store the polar angular values</param>
/// <param name="cxMag">The vec2 vector to store the polar magnitude values</param>
/// <param name="cxTrn">The vec2 vector to store the polar translation values</param>
static void ConvertLinearToPolar(Ember<T>* embers, size_t size, size_t xfi, size_t cflag, vector<v2T>& cxAng, vector<v2T>& cxMag, vector<v2T>& cxTrn)
static void ConvertLinearToPolar(const Ember<T>* embers, size_t size, size_t xfi, size_t cflag, vector<v2T>& cxAng, vector<v2T>& cxMag, vector<v2T>& cxTrn)
{
if (size == cxAng.size() &&
size == cxMag.size() &&
@ -765,7 +765,7 @@ public:
/// <param name="cxMag">The vec2 vector to store the polar magnitude values</param>
/// <param name="cxTrn">The vec2 vector to store the polar translation values</param>
/// <param name="store">The Affine2D to store the inerpolated values in</param>
static void InterpAndConvertBack(vector<T>& coefs, vector<v2T>& cxAng, vector<v2T>& cxMag, vector<v2T>& cxTrn, Affine2D<T>& store)
static void InterpAndConvertBack(const vector<T>& coefs, const vector<v2T>& cxAng, const vector<v2T>& cxMag, const vector<v2T>& cxTrn, Affine2D<T>& store)
{
size_t size = coefs.size();
glm::length_t i, col, accmode[2] = { 0, 0 };

View File

@ -56,7 +56,7 @@ class EMBER_API QTIsaac
public:
enum { N = (1 << ALPHA) };
UintBytes m_Cache;
size_t m_LastIndex;
size_t m_LastIndex = 0;
/// <summary>
/// The structure which holds all of the random information.
@ -85,7 +85,6 @@ public:
QTIsaac(T a = 0, T b = 0, T c = 0, T* s = nullptr)
{
Srand(a, b, c, s);
m_LastIndex = 0;
m_Cache.Uint = Rand();
RandByte();//Need to call at least once so other libraries can link.
}

View File

@ -52,18 +52,11 @@ class EMBER_API Iterator
{
public:
/// <summary>
/// Empty constructor.
/// Empty constructor and virtual destructor so proper derived class destructors get called.
/// </summary>
Iterator()
{
}
/// <summary>
/// Empty virtual destructor so proper derived class destructors get called.
/// </summary>
virtual ~Iterator()
{
}
Iterator() = default;
virtual ~Iterator() = default;
Iterator(const Iterator<T>& iter) = delete;
/// <summary>
/// Accessors.

View File

@ -25,8 +25,6 @@ public:
/// </summary>
Palette()
{
m_Name = "-";
m_Index = -1;
m_Entries.resize(COLORMAP_LENGTH);
Clear();
}
@ -119,12 +117,9 @@ public:
}
/// <summary>
/// Empty destructor.
/// Needed to eliminate warnings about inlining.
/// </summary>
~Palette()
{
}
~Palette() = default;
/// <summary>
/// Default assignment operator.
@ -149,7 +144,7 @@ public:
m_Index = palette.m_Index;
m_Name = palette.m_Name;
m_Filename = palette.m_Filename;
CopyVec(m_Entries, palette.m_Entries);
CopyCont(m_Entries, palette.m_Entries);
return *this;
}
@ -163,6 +158,16 @@ public:
return m_Entries[i];
}
/// <summary>
/// Convenience [] operator to index into the color entries vector in a const context.
/// </summary>
/// <param name="i">The index to get</param>
/// <returns>The color value at the specified index</returns>
const v4T& operator[] (size_t i) const
{
return m_Entries[i];
}
/// <summary>
/// Convenience * operator to get a pointer to the beginning of the color entries vector.
/// </summary>
@ -421,7 +426,7 @@ public:
/// </summary>
/// <param name="rgb">The RGB buffer</param>
/// <param name="hsv">The HSV buffer</param>
static void RgbToHsv(T* rgb, T* hsv)
static void RgbToHsv(const T* rgb, T* hsv)
{
RgbToHsv(rgb[0], rgb[1], rgb[2], hsv[0], hsv[1], hsv[2]);
}
@ -576,9 +581,9 @@ public:
}
}
int m_Index;//Index in the xml palette file of this palette, use -1 for random.
string m_Name;//Name of this palette.
int m_Index = -1;//Index in the xml palette file of this palette, use -1 for random.
string m_Name = "-";//Name of this palette.
shared_ptr<string> m_Filename;//Name of the parent file this palette came from, can be empty.
vector<v4T> m_Entries;//Storage for the color values.
vector<v4T> m_Entries;
};
}

View File

@ -28,6 +28,9 @@ public:
Add(string(m_DefaultFilename));
}
~PaletteList() = default;
PaletteList(const PaletteList<T>& paletteList) = delete;
/// <summary>
/// Read an Xml palette file into memory.
/// This must be called before any palette file usage.

View File

@ -25,10 +25,8 @@ public:
/// <summary>
/// Constructor to initialize spatial and color coordinates to zero, with full visibility.
/// </summary>
Point()
{
Init();
}
Point() = default;
~Point() = default;
/// <summary>
/// Default copy constructor.
@ -75,29 +73,16 @@ public:
m_ColorX = point.m_ColorX;
//m_ColorY = point.m_ColorY;
m_VizAdjusted = point.m_VizAdjusted;
return *this;
}
/// <summary>
/// Set spatial and color coordinates to zero, with full visibility.
/// </summary>
void Init()
{
m_X = 0;
m_Y = 0;
m_Z = 0;
m_ColorX = 0;
//m_ColorY = 0;
m_VizAdjusted = 1;
}
T m_X;
T m_Y;
T m_Z;
T m_ColorX;
//Set spatial and color coordinates to zero, with full visibility.
T m_X = 0;
T m_Y = 0;
T m_Z = 0;
T m_ColorX = 0;
//T m_ColorY;
T m_VizAdjusted;
T m_VizAdjusted = 1;
};
/// <summary>
@ -132,10 +117,10 @@ template <typename T>
struct EMBER_API Color : public v4T
{
#ifndef _WIN32
using v4T::r;
using v4T::g;
using v4T::b;
using v4T::a;
using v4T::r;
using v4T::g;
using v4T::b;
using v4T::a;
#endif
public:
/// <summary>

View File

@ -3,27 +3,6 @@
namespace EmberNs
{
/// <summary>
/// Constructor that sets default values and allocates iterators.
/// The thread count is set to the number of cores detected on the system.
/// </summary>
template <typename T, typename bucketT>
Renderer<T, bucketT>::Renderer()
{
m_PixelAspectRatio = 1;
m_StandardIterator = unique_ptr<StandardIterator<T>>(new StandardIterator<T>());
m_XaosIterator = unique_ptr<XaosIterator<T>>(new XaosIterator<T>());
m_Iterator = m_StandardIterator.get();
}
/// <summary>
/// Virtual destructor so derived class destructors get called.
/// </summary>
template <typename T, typename bucketT>
Renderer<T, bucketT>::~Renderer()
{
}
/// <summary>
/// Non-virtual processing functions.
/// </summary>
@ -89,7 +68,7 @@ void Renderer<T, bucketT>::ComputeBounds()
////Check the size of the density estimation filter.
////If the radius of the density estimation filter is greater than the
////gutter width, have to pad with more. Otherwise, use the same value.
//for (auto& ember : m_Embers)
//for (auto& ember : *m_EmbersP)
// maxDEFilterWidth = std::max<size_t>(size_t(ceil(ember.m_MaxRadDE) * m_Ember.m_Supersample), maxDEFilterWidth);
//
////Need an extra ss = (int)floor(m_Supersample / 2.0) of pixels so that a local iteration count for DE can be determined.//SMOULDER
@ -162,7 +141,7 @@ void Renderer<T, bucketT>::ComputeCamera()
/// However, changing only the brightness and setting action to ACCUM_ONLY is perfectly fine.
/// </param>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::SetEmber(Ember<T>& ember, eProcessAction action)
void Renderer<T, bucketT>::SetEmber(const Ember<T>& ember, eProcessAction action)
{
ChangeVal([&]
{
@ -170,26 +149,64 @@ void Renderer<T, bucketT>::SetEmber(Ember<T>& ember, eProcessAction action)
m_Embers.push_back(ember);
m_Embers[0].m_TemporalSamples = 1;//Set temporal samples here to 1 because using the real value only makes sense when using a vector of Embers for animation.
m_Ember = m_Embers[0];
m_EmbersP = &m_Embers;
}, action);
}
/// <summary>
/// Set the vector of embers and set the m_Ember member to a copy of the first element.
/// Copy the embers in the passed in container to the internal vector of embers
/// and set the m_Ember member to a copy of the first element.
/// Reset the rendering process.
/// </summary>
/// <param name="embers">The vector of embers</param>
/// <param name="embers">The container of embers to be copied</param>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::SetEmber(vector<Ember<T>>& embers)
template <typename C>
void Renderer<T, bucketT>::SetEmber(const C& embers)
{
ChangeVal([&]
{
m_Embers = embers;
CopyCont(m_Embers, embers);
m_EmbersP = &m_Embers;
if (!m_Embers.empty())
m_Ember = m_Embers[0];
}, eProcessAction::FULL_RENDER);
}
/// <summary>
/// Move the embers in the passed in vector to the internal vector of embers
/// and set the m_Ember member to a copy of the first element.
/// Reset the rendering process.
/// This is preferred over SetEmber when the size of embers is large and/or
/// the caller no longer needs to use the argument after this function returns.
/// </summary>
/// <param name="embers">The vector of embers to be moved</param>
template <typename T, typename bucketT>
void Renderer<T, bucketT>::MoveEmbers(vector<Ember<T>>& embers)
{
ChangeVal([&]
{
m_Embers = std::move(embers);
m_EmbersP = &m_Embers;
if (!m_Embers.empty())
m_Ember = m_Embers[0];
}, eProcessAction::FULL_RENDER);
}
template <typename T, typename bucketT>
void Renderer<T, bucketT>::SetExternalEmbersPointer(vector<Ember<T>>* embers)
{
ChangeVal([&]
{
m_Embers.clear();
m_EmbersP = embers;
if (!m_EmbersP->empty())
m_Ember = (*m_EmbersP)[0];
}, eProcessAction::FULL_RENDER);
}
/// <summary>
/// Create the density filter if the current filter parameters differ
/// from the last density filter created.
@ -213,7 +230,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<bucketT>>(new DensityFilter<bucketT>(bucketT(m_Ember.m_MinRadDE), bucketT(m_Ember.m_MaxRadDE), bucketT(m_Ember.m_CurveDE), m_Ember.m_Supersample));
m_DensityFilter = make_unique<DensityFilter<bucketT>>(bucketT(m_Ember.m_MinRadDE), bucketT(m_Ember.m_MaxRadDE), bucketT(m_Ember.m_CurveDE), m_Ember.m_Supersample);
newAlloc = true;
}
@ -384,7 +401,7 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
//Vib, gam and background are normally summed for each temporal sample. However if iteration is skipped, make sure to get the latest.
if ((filterAndAccumOnly || accumOnly) && TemporalSamples() == 1)//Disallow jumping when temporal samples > 1.
{
m_Ember = m_Embers[0];
m_Ember = (*m_EmbersP)[0];
m_Vibrancy = Vibrancy();
m_Gamma = Gamma();
m_Background = m_Ember.m_Background;
@ -398,8 +415,8 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
//it.Tic();
//Interpolate.
if (m_Embers.size() > 1)
Interpolater<T>::Interpolate(m_Embers, T(time), 0, m_Ember);
if (m_EmbersP->size() > 1)
Interpolater<T>::Interpolate(*m_EmbersP, T(time), 0, m_Ember);
//it.Toc("Interp 1");
@ -436,8 +453,8 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
//Interpolate and get an ember for DE purposes.
//Additional interpolation will be done in the temporal samples loop.
//it.Tic();
if (m_Embers.size() > 1)
Interpolater<T>::Interpolate(m_Embers, deTime, 0, m_Ember);
if (m_EmbersP->size() > 1)
Interpolater<T>::Interpolate(*m_EmbersP, deTime, 0, m_Ember);
//it.Toc("Interp 2");
ClampGteRef<T>(m_Ember.m_MinRadDE, 0);
@ -461,8 +478,8 @@ eRenderStatus Renderer<T, bucketT>::Run(vector<byte>& finalImage, double time, s
//Interpolate again.
//it.Tic();
if (TemporalSamples() > 1 && m_Embers.size() > 1)
Interpolater<T>::Interpolate(m_Embers, temporalTime, 0, m_Ember);//This will perform all necessary precalcs via the ember/xform/variation assignment operators.
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.
//it.Toc("Interp 3");
@ -678,16 +695,15 @@ Finish:
/// Run() should have completed before calling this.
/// </summary>
/// <param name="printEditDepth">The depth of the edit tags</param>
/// <param name="intPalette">If true use integers instead of floating point numbers when embedding a non-hex formatted palette, else use floating point numbers.</param>
/// <param name="hexPalette">If true, embed a hexadecimal palette instead of Xml Color tags, else use Xml color tags.</param>
/// <returns>The EmberImageComments object with image comments filled out</returns>
template <typename T, typename bucketT>
EmberImageComments Renderer<T, bucketT>::ImageComments(const EmberStats& stats, size_t printEditDepth, bool intPalette, bool hexPalette)
EmberImageComments Renderer<T, bucketT>::ImageComments(const EmberStats& stats, size_t printEditDepth, bool hexPalette)
{
ostringstream ss;
EmberImageComments comments;
ss.imbue(std::locale(""));
comments.m_Genome = m_EmberToXml.ToString(m_Ember, "", printEditDepth, false, intPalette, hexPalette);
comments.m_Genome = m_EmberToXml.ToString(m_Ember, "", printEditDepth, false, hexPalette);
ss << (double(stats.m_Badvals) / double(stats.m_Iters));//Percentage of bad values to iters.
comments.m_Badvals = ss.str(); ss.str("");
ss << stats.m_Iters;
@ -1702,8 +1718,12 @@ void Renderer<T, bucketT>::CurveAdjust(bucketT& a, const glm::length_t& index)
//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>;
template EMBER_API void Renderer<float, float>::SetEmber(const vector<Ember<float>>& embers);
template EMBER_API void Renderer<float, float>::SetEmber(const list<Ember<float>>& embers);
#ifdef DO_DOUBLE
template EMBER_API class Renderer<double, float>;
template EMBER_API void Renderer<double, float>::SetEmber(const vector<Ember<double>>& embers);
template EMBER_API void Renderer<double, float>::SetEmber(const list<Ember<double>>& embers);
#endif
}

View File

@ -43,10 +43,12 @@ namespace EmberNs
template <typename T, typename bucketT>
class EMBER_API Renderer : public RendererBase
{
//using EmberReport::m_ErrorReport;
public:
Renderer();
virtual ~Renderer();
Renderer() = default;
Renderer(const Renderer<T, bucketT>& renderer) = delete;
Renderer<T, bucketT>& operator = (const Renderer<T, bucketT>& renderer) = delete;
virtual ~Renderer() = default;
//Non-virtual processing functions.
void AddEmber(Ember<T>& ember);
@ -56,14 +58,17 @@ public:
virtual void ComputeBounds() override;
virtual void ComputeQuality() override;
virtual void ComputeCamera() override;
virtual void SetEmber(Ember<T>& ember, eProcessAction action = eProcessAction::FULL_RENDER) override;
virtual void SetEmber(vector<Ember<T>>& embers) override;
virtual void SetEmber(const Ember<T>& ember, eProcessAction action = eProcessAction::FULL_RENDER) override;
template <typename C>
void SetEmber(const C& embers);
void MoveEmbers(vector<Ember<T>>& embers);
void SetExternalEmbersPointer(vector<Ember<T>>* embers);
virtual bool CreateDEFilter(bool& newAlloc) override;
virtual bool CreateSpatialFilter(bool& newAlloc) override;
virtual bool CreateTemporalFilter(bool& newAlloc) override;
virtual size_t HistBucketSize() const override { return sizeof(tvec4<bucketT, glm::defaultp>); }
virtual eRenderStatus Run(vector<byte>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) override;
virtual EmberImageComments ImageComments(const EmberStats& stats, size_t printEditDepth = 0, bool intPalette = false, bool hexPalette = true) override;
virtual EmberImageComments ImageComments(const EmberStats& stats, size_t printEditDepth = 0, bool hexPalette = true) override;
protected:
//New virtual functions to be overridden in derived renderers that use the GPU, but not accessed outside.
@ -158,7 +163,7 @@ protected:
T m_Scale;
T m_PixelsPerUnitX;
T m_PixelsPerUnitY;
T m_PixelAspectRatio;
T m_PixelAspectRatio = 1;
T m_LowerLeftX;
T m_LowerLeftY;
T m_UpperRightX;
@ -173,12 +178,16 @@ protected:
Ember<T> m_Ember;
Ember<T> m_TempEmber;
Ember<T> m_LastEmber;
private:
vector<Ember<T>> m_Embers;
protected:
vector<Ember<T>>* m_EmbersP = &m_Embers;
vector<Ember<T>> m_ThreadEmbers;
CarToRas<T> m_CarToRas;
Iterator<T>* m_Iterator;
unique_ptr<StandardIterator<T>> m_StandardIterator;
unique_ptr<XaosIterator<T>> m_XaosIterator;
unique_ptr<StandardIterator<T>> m_StandardIterator = make_unique<StandardIterator<T>>();
unique_ptr<XaosIterator<T>> m_XaosIterator = make_unique<XaosIterator<T>>();
Iterator<T>* m_Iterator = m_StandardIterator.get();
Palette<bucketT> m_Dmap, m_Csa;
vector<tvec4<bucketT, glm::defaultp>> m_HistBuckets;
vector<tvec4<bucketT, glm::defaultp>> m_AccumulatorBuckets;

View File

@ -8,31 +8,8 @@ namespace EmberNs
/// The thread count is set to the number of cores detected on the system.
/// </summary>
RendererBase::RendererBase()
: m_TaskGroup(new tbb::task_group)
{
m_Abort = false;
m_LockAccum = false;
m_EarlyClip = false;
m_YAxisUp = false;
m_InsertPalette = false;
m_ReclaimOnResize = false;
m_CurvesSet = false;
m_NumChannels = 3;
m_BytesPerChannel = 1;
m_SuperSize = 0;
m_Transparency = false;
ThreadCount(Timing::ProcessorCount());
m_Callback = nullptr;
m_ProgressParameter = nullptr;
m_LastTemporalSample = 0;
m_LastIter = 0;
m_LastIterPercent = 0;
m_InteractiveFilter = eInteractiveFilter::FILTER_LOG;
m_Priority = eThreadPriority::NORMAL;
m_ProcessState = eProcessState::NONE;
m_ProcessAction = eProcessAction::FULL_RENDER;
m_InRender = false;
m_InFinalAccum = false;
}
/// <summary>

View File

@ -21,10 +21,13 @@ namespace EmberNs
class EMBER_API RenderCallback
{
public:
RenderCallback() = default;
RenderCallback(RenderCallback& callback) = delete;
/// <summary>
/// Virtual destructor to ensure anything declared in derived classes gets cleaned up.
/// </summary>
virtual ~RenderCallback() { }
virtual ~RenderCallback() = default;
/// <summary>
/// Empty progress function to be implemented in derived classes to take action on progress updates.
@ -91,10 +94,11 @@ enum class eRendererType : et { CPU_RENDERER, OPENCL_RENDERER };
/// </summary>
class EMBER_API RendererBase : public EmberReport
{
//using EmberReport::m_ErrorReport;
public:
RendererBase();
virtual ~RendererBase() { }
RendererBase(const RendererBase& renderer) = delete;
RendererBase& operator = (const RendererBase& renderer) = delete;
virtual ~RendererBase() = default;
//Non-virtual processing functions.
void ChangeVal(std::function<void(void)> func, eProcessAction action);
@ -106,10 +110,8 @@ public:
//Virtual processing functions.
virtual bool Ok() const;
virtual size_t MemoryAvailable();
virtual void SetEmber(Ember<float>& ember, eProcessAction action = eProcessAction::FULL_RENDER) { }
virtual void SetEmber(vector<Ember<float>>& embers) { }
virtual void SetEmber(Ember<double>& ember, eProcessAction action = eProcessAction::FULL_RENDER) { }
virtual void SetEmber(vector<Ember<double>>& embers) { }
virtual void SetEmber(const Ember<float>& ember, eProcessAction action = eProcessAction::FULL_RENDER) { }
virtual void SetEmber(const Ember<double>& ember, eProcessAction action = eProcessAction::FULL_RENDER) { }
virtual bool RandVec(vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>>& randVec);
//Abstract processing functions.
@ -120,7 +122,7 @@ public:
virtual void ComputeQuality() = 0;
virtual void ComputeCamera() = 0;
virtual eRenderStatus Run(vector<byte>& finalImage, double time = 0, size_t subBatchCountOverride = 0, bool forceOutput = false, size_t finalOffset = 0) = 0;
virtual EmberImageComments ImageComments(const EmberStats& stats, size_t printEditDepth = 0, bool intPalette = false, bool hexPalette = true) = 0;
virtual EmberImageComments ImageComments(const EmberStats& stats, size_t printEditDepth = 0, bool hexPalette = true) = 0;
virtual DensityFilterBase* GetDensityFilter() = 0;
//Non-virtual renderer properties, getters only.
@ -193,41 +195,41 @@ public:
bool InRender();
bool InFinalAccum();
void* m_ProgressParameter;
void* m_ProgressParameter = nullptr;
protected:
bool m_EarlyClip;
bool m_YAxisUp;
bool m_Transparency;
bool m_LockAccum;
bool m_InRender;
bool m_InFinalAccum;
bool m_InsertPalette;
bool m_ReclaimOnResize;
bool m_CurvesSet;
volatile bool m_Abort;
bool m_EarlyClip = false;
bool m_YAxisUp = false;
bool m_Transparency = false;
bool m_LockAccum = false;
bool m_InRender = false;
bool m_InFinalAccum = false;
bool m_InsertPalette = false;
bool m_ReclaimOnResize = false;
bool m_CurvesSet = false;
volatile bool m_Abort = false;
size_t m_SuperRasW;
size_t m_SuperRasH;
size_t m_SuperSize;
size_t m_SuperSize = 0;
size_t m_GutterWidth;
size_t m_DensityFilterOffset;
size_t m_NumChannels;
size_t m_BytesPerChannel;
size_t m_NumChannels = 3;
size_t m_BytesPerChannel = 1;
size_t m_ThreadsToUse;
size_t m_VibGamCount;
size_t m_LastTemporalSample;
size_t m_LastIter;
double m_LastIterPercent;
eThreadPriority m_Priority;
eProcessAction m_ProcessAction;
eProcessState m_ProcessState;
eInteractiveFilter m_InteractiveFilter;
size_t m_LastTemporalSample = 0;
size_t m_LastIter = 0;
double m_LastIterPercent = 0;
eThreadPriority m_Priority = eThreadPriority::NORMAL;
eProcessAction m_ProcessAction = eProcessAction::FULL_RENDER;
eProcessState m_ProcessState = eProcessState::NONE;
eInteractiveFilter m_InteractiveFilter = eInteractiveFilter::FILTER_LOG;
EmberStats m_Stats;
RenderCallback* m_Callback;
RenderCallback* m_Callback = nullptr;
vector<size_t> m_SubBatch;
vector<size_t> m_BadVals;
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> m_Rand;
auto_ptr<tbb::task_group> m_TaskGroup;
unique_ptr<tbb::task_group> m_TaskGroup = make_unique<tbb::task_group>();
std::recursive_mutex m_RenderingCs, m_AccumCs, m_FinalAccumCs, m_ResizeCs;
Timing m_RenderTimer, m_IterTimer, m_ProgressTimer;
};

View File

@ -65,19 +65,14 @@ public:
: m_VariationList(VariationList<T>::Instance())
{
Timing t;
m_Smooth = true;
m_SheepGen = -1;
m_SheepId = -1;
m_Stagger = 0;
m_OffsetX = 0;
m_OffsetY = 0;
m_PaletteList.Add(palettePath);
m_StandardIterator = unique_ptr<StandardIterator<T>>(new StandardIterator<T>());
m_XaosIterator = unique_ptr<XaosIterator<T>>(new XaosIterator<T>());
m_Renderer = unique_ptr<Renderer<T, bucketT>>(renderer);
m_Rand = QTIsaac<ISAAC_SIZE, ISAAC_INT>(ISAAC_INT(t.Tic()), ISAAC_INT(t.Tic() * 2), ISAAC_INT(t.Tic() * 3));
}
SheepTools(const SheepTools& sheepTools) = delete;
SheepTools<T, bucketT>& operator = (const SheepTools<T, bucketT>& sheepTools) = delete;
/// <summary>
/// Create the linear default ember with a random palette.
/// </summary>
@ -1329,12 +1324,12 @@ public:
}
private:
bool m_Smooth;
intmax_t m_SheepGen;
intmax_t m_SheepId;
T m_Stagger;
T m_OffsetX;
T m_OffsetY;
bool m_Smooth = true;
intmax_t m_SheepGen = -1;
intmax_t m_SheepId = -1;
T m_Stagger = 0;
T m_OffsetX = 0;
T m_OffsetY = 0;
string m_Nick;
string m_Url;
string m_Id;
@ -1345,8 +1340,8 @@ private:
vector<uint> m_Hist;
EmberToXml<T> m_EmberToXml;
Iterator<T>* m_Iterator;
unique_ptr<StandardIterator<T>> m_StandardIterator;
unique_ptr<XaosIterator<T>> m_XaosIterator;
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;
QTIsaac<ISAAC_SIZE, ISAAC_INT> m_Rand;
PaletteList<T> m_PaletteList;

View File

@ -72,12 +72,16 @@ class EMBER_API EmberImageComments
{
public:
/// <summary>
/// Empty destructor.
/// Basic defaults.
/// </summary>
EmberImageComments() = default;
EmberImageComments(const EmberImageComments& comments) = default;
EmberImageComments& operator = (const EmberImageComments& comments) = default;
/// <summary>
/// Needed to eliminate warnings about inlining.
/// </summary>
~EmberImageComments()
{
}
~EmberImageComments() = default;
/// <summary>
/// Set all values to the empty string.
@ -304,81 +308,105 @@ static bool ReadFile(const char* filename, string& buf, bool nullTerminate = tru
}
/// <summary>
/// Clear dest and copy all of the elements of vector source with elements of type U to the vector
/// dest with elements of type T.
/// Thin wrapper around std::advance that returns the advanced iterator.
/// Note the passed in iterator is constant so it will not be changed, unlike
/// std::advance does.
/// </summary>
/// <param name="dest">The vector of type T to copy to</param>
/// <param name="source">The vector of type U to copy from</param>
template <typename T, typename U>
static void CopyVec(vector<T>& dest, const vector<U>& source)
/// <param name="it">A const reference to an iterator, a copy of which will be advanced.</param>
/// <param name="off">How far to move the iterator forward</param>
/// <returns>A copy of the passed in iterator, advanced the specified number of elements</returns>
template<class iter, class diff>
static iter Advance(const iter& it, diff off)
{
dest.clear();
dest.resize(source.size());
for (size_t i = 0; i < source.size(); i++)
dest[i] = static_cast<T>(source[i]);//Valid assignment operator between T and U types must be defined somewhere.
auto temp = it;
std::advance(temp, off);
return temp;
}
/// <summary>
/// Clear dest and copy all of the elements of vector source with elements of type U to the vector
/// Clear dest and copy all of the elements of container source with elements of type U to the container
/// dest with elements of type T.
/// Call a function on each element after it's been copied.
/// </summary>
/// <param name="dest">The vector of type T to copy to</param>
/// <param name="source">The vector of type U to copy from</param>
/// <param name="perElementOperation">A function to call on each element after it's copied</param>
template <typename T, typename U>
static void CopyVec(vector<T>& dest, const vector<U>& source, std::function<void(T& t)> perElementOperation)
/// <param name="dest">The container of type Cdest with elements of type T to copy to</param>
/// <param name="source">The container of type Csource with elements of type U to copy from</param>
template <typename T, typename U, typename Dalloc, typename Salloc, template <typename, typename> class Cdest, template <typename, typename> class Csource>
static void CopyCont(Cdest<T, Dalloc>& dest, const Csource<U, Salloc>& source)
{
dest.clear();
dest.resize(source.size());
auto it1 = source.begin();
auto it2 = dest.begin();
for (size_t i = 0; i < source.size(); i++)
for (; it1 != source.end(); it1++, it2++)
*it2 = static_cast<T>(*it1);//Valid assignment operator between T and U types must be defined somewhere.
}
/// <summary>
/// Clear dest and copy all of the elements of container source with elements of type U to the container
/// dest with elements of type T.
/// Call a function on each element after it's been copied.
/// </summary>
/// <param name="dest">The container of type Cdest with elements of type T to copy to</param>
/// <param name="source">The container of type Csource with elements of type U to copy from</param>
/// <param name="perElementOperation">A function to call on each element after it's copied</param>
template <typename T, typename U, typename Dalloc, typename Salloc, template <typename, typename> class Cdest, template <typename, typename> class Csource>
static void CopyCont(Cdest<T, Dalloc>& dest, const Csource<U, Salloc>& source, std::function<void(T& t)> perElementOperation)
{
dest.clear();
dest.resize(source.size());
auto it1 = source.begin();
auto it2 = dest.begin();
for (; it1 != source.end(); it1++, it2++)
{
dest[i] = static_cast<T>(source[i]);//Valid assignment operator between T and U types must be defined somewhere.
perElementOperation(dest[i]);
*it2 = static_cast<T>(*it1);//Valid assignment operator between T and U types must be defined somewhere.
perElementOperation(*it2);
}
}
/// <summary>
/// Clear a vector of pointers to any type by checking each element for nullptr and calling delete on it, then clearing the entire vector.
/// Clear a container of pointers to any type by checking each element for nullptr and calling delete on it, then clearing the entire vector.
/// Optionally call array delete if the elements themselves are pointers to dynamically allocated arrays.
/// </summary>
/// <param name="vec">The vector to be cleared</param>
/// <param name="arrayDelete">Whether to call delete or delete []. Default: false.</param>
template <typename T>
static void ClearVec(vector<T*>& vec, bool arrayDelete = false)
template <typename T, typename Alloc, template <typename, typename> class C>
static void ClearVec(C<T*, Alloc>& cont, bool arrayDelete = false)
{
for (size_t i = 0; i < vec.size(); i++)
for (auto& it : cont)
{
if (vec[i])
if (it)
{
if (arrayDelete)
delete [] vec[i];
delete [] it;
else
delete vec[i];
delete it;
}
vec[i] = nullptr;
it = nullptr;
}
vec.clear();
cont.clear();
}
/// <summary>
/// Determine whether all elements in two containers are equal.
/// The container types do not have to match, but their element types do.
/// </summary>
/// <param name="c1">The first collection to compare</param>
/// <param name="c2">The second collection to compare</param>
/// <returns>True if the sizes and all elements in both collections are equal, else false.</returns>
template <typename T>
static bool Equal(const T& c1, const T& c2)
template <typename T, typename C1Alloc, typename C2Alloc, template <typename, typename> class C1, template <typename, typename> class C2>
static bool Equal(const C1<T, C1Alloc>& c1, const C2<T, C2Alloc>& c2)
{
bool equal = c1.size() == c2.size();
if (equal)
{
for (auto it1 = c1.begin(), it2 = c2.begin(); it1 != c1.end(); ++it1, ++it2)
auto it1 = c1.begin();
auto it2 = c2.begin();
for (; it1 != c1.end(); ++it1, ++it2)
{
if (*it1 != *it2)
{
@ -443,10 +471,7 @@ static inline T Clamp(T val, T min, T max)
}
template <>
#ifdef _WIN32
static
#endif
float Clamp<float>(float val, float min, float max)
STATIC float Clamp<float>(float val, float min, float max)
{
if (val < min)
return min;
@ -459,10 +484,7 @@ float Clamp<float>(float val, float min, float max)
}
template <>
#ifdef _WIN32
static
#endif
double Clamp<double>(double val, double min, double max)
STATIC double Clamp<double>(double val, double min, double max)
{
if (val < min)
return min;
@ -512,10 +534,7 @@ static inline void ClampRef(T& val, T min, T max)
}
template <>
#ifdef _WIN32
static
#endif
void ClampRef<float>(float& val, float min, float max)
STATIC void ClampRef<float>(float& val, float min, float max)
{
if (val < min)
val = min;
@ -526,10 +545,7 @@ void ClampRef<float>(float& val, float min, float max)
}
template <>
#ifdef _WIN32
static
#endif
void ClampRef<double>(double& val, double min, double max)
STATIC void ClampRef<double>(double& val, double min, double max)
{
if (val < min)
val = min;
@ -552,20 +568,14 @@ static inline void ClampLteRef(T& val, T lte)
}
template <>
#ifdef _WIN32
static
#endif
void ClampLteRef<float>(float& val, float lte)
STATIC void ClampLteRef<float>(float& val, float lte)
{
if (val > lte || !std::isfinite(val))
val = lte;
}
template <>
#ifdef _WIN32
static
#endif
void ClampLteRef<double>(double& val, double lte)
STATIC void ClampLteRef<double>(double& val, double lte)
{
if (val > lte || !std::isfinite(val))
val = lte;
@ -585,10 +595,7 @@ static inline T ClampGte(T val, T gte)
}
template <>
#ifdef _WIN32
static
#endif
float ClampGte<float>(float val, float gte)
STATIC float ClampGte<float>(float val, float gte)
{
if (val < gte || !std::isfinite(val))
return gte;
@ -597,10 +604,7 @@ float ClampGte<float>(float val, float gte)
}
template <>
#ifdef _WIN32
static
#endif
double ClampGte<double>(double val, double gte)
STATIC double ClampGte<double>(double val, double gte)
{
if (val < gte || !std::isfinite(val))
return gte;
@ -621,20 +625,14 @@ static inline void ClampGteRef(T& val, T gte)
}
template <>
#ifdef _WIN32
static
#endif
void ClampGteRef<float>(float& val, float gte)
STATIC void ClampGteRef<float>(float& val, float gte)
{
if (val < gte || !std::isfinite(val))
val = gte;
}
template <>
#ifdef _WIN32
static
#endif
void ClampGteRef<double>(double& val, double gte)
STATIC void ClampGteRef<double>(double& val, double gte)
{
if (val < gte || !std::isfinite(val))
val = gte;
@ -721,19 +719,13 @@ static inline T SafeTan(T x)
}
template <>
#ifdef _WIN32
static
#endif
float SafeTan<float>(float x)
STATIC float SafeTan<float>(float x)
{
return std::tan(Clamp<float>(x, FLOAT_MIN_TAN, FLOAT_MAX_TAN));
}
template <>
#ifdef _WIN32
static
#endif
double SafeTan<double>(double x)
STATIC double SafeTan<double>(double x)
{
return std::tan(x);
}
@ -940,10 +932,7 @@ static inline T Arg(char* name, T def)
/// <param name="def">The default value to return if the environment variable was not present</param>
/// <returns>The value of the specified environment variable if found, else default</returns>
template <>
#ifdef _WIN32
static
#endif
bool Arg<bool>(char* name, bool def)
STATIC bool Arg<bool>(char* name, bool def)
{
return (Arg<int>(name, -999) != -999) ? true : def;
}
@ -955,10 +944,7 @@ bool Arg<bool>(char* name, bool def)
/// <param name="def">The default value to return if the environment variable was not present</param>
/// <returns>The value of the specified environment variable if found, else default</returns>
template <>
#ifdef _WIN32
static
#endif
string Arg<string>(char* name, string def)
STATIC string Arg<string>(char* name, string def)
{
char* ch;
string returnVal;

View File

@ -69,9 +69,9 @@ public:
T pe = 1,
T pc = 0,
T pf = 0)
: Xform()
{
Init();
m_Weight = weight;
m_ColorX = colorX;
m_ColorSpeed = colorSpeed;
@ -184,8 +184,8 @@ public:
if (!m_ParentEmber && (typeid(T) == typeid(U)))
m_ParentEmber = reinterpret_cast<Ember<T>*>(xform.ParentEmber());
CopyVec<T, U>(m_Xaos, xform.XaosVec());
CopyVec(m_Motion, xform.m_Motion);
CopyCont(m_Xaos, xform.XaosVec());//<T, U> needed?//TODO
CopyCont(m_Motion, xform.m_Motion);
m_Name = xform.m_Name;
return *this;
}

View File

@ -296,14 +296,15 @@ public:
}
/// <summary>
/// Parse the specified buffer and place the results in the vector of embers passed in.
/// Parse the specified buffer and place the results in the container of embers passed in.
/// </summary>
/// <param name="buf">The buffer to parse</param>
/// <param name="filename">Full path and filename, optionally empty</param>
/// <param name="embers">The newly constructed embers based on what was parsed</param>
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.</param>
/// <returns>True if there were no errors, else false.</returns>
bool Parse(byte* buf, const char* filename, vector<Ember<T>>& embers, bool useDefaults = true)
template <typename Alloc, template <typename, typename> class C>
bool Parse(byte* buf, const char* filename, C<Ember<T>, Alloc>& embers, bool useDefaults = true)
{
char* bn;
const char* xmlPtr;
@ -318,7 +319,7 @@ public:
//Parse XML string into internal document.
xmlPtr = CX(&buf[0]);
bufSize = strlen(xmlPtr);
embers.reserve(bufSize / 2500);//The Xml text for an ember is around 2500 bytes, but can be much more. Pre-allocate to aovid unnecessary resizing.
//embers.reserve(bufSize / 2500);//The Xml text for an ember is around 2500 bytes, but can be much more. Pre-allocate to aovid unnecessary resizing.
doc = xmlReadMemory(xmlPtr, int(bufSize), filename, "ISO-8859-1", XML_PARSE_NONET);//Forbid network access during read.
//t.Toc("xmlReadMemory");
@ -336,6 +337,8 @@ public:
ScanForEmberNodes(rootnode, bn, embers, useDefaults);
xmlFreeDoc(doc);
emberSize = embers.size();
auto b = embers.begin();
auto secondToLast = Advance(embers.begin(), emberSize - 2);
//t.Toc("ScanForEmberNodes");
//Check to see if the first control point or the second-to-last
@ -343,11 +346,11 @@ public:
//and should be reset to linear (with a warning).
if (emberSize > 0)
{
if (embers[0].m_Interp == eInterp::EMBER_INTERP_SMOOTH)
embers[0].m_Interp = eInterp::EMBER_INTERP_LINEAR;
if (b->m_Interp == eInterp::EMBER_INTERP_SMOOTH)
b->m_Interp = eInterp::EMBER_INTERP_LINEAR;
if (emberSize >= 2 && embers[emberSize - 2].m_Interp == eInterp::EMBER_INTERP_SMOOTH)
embers[emberSize - 2].m_Interp = eInterp::EMBER_INTERP_LINEAR;
if (emberSize >= 2 && secondToLast->m_Interp == eInterp::EMBER_INTERP_SMOOTH)
secondToLast->m_Interp = eInterp::EMBER_INTERP_LINEAR;
}
//Finally, ensure that consecutive 'rotate' parameters never exceed
@ -355,17 +358,22 @@ public:
//An adjustment of +/- 360 degrees is made until this is true.
if (emberSize > 1)
{
for (size_t i = 1; i < emberSize; i++)
auto prev = embers.begin();
auto second = Advance(embers.begin(), 1);
for (auto it = second; it != embers.end(); ++it)
{
//Only do this adjustment if not in compat mode.
if (embers[i - 1].m_AffineInterp != eAffineInterp::AFFINE_INTERP_COMPAT && embers[i - 1].m_AffineInterp != eAffineInterp::AFFINE_INTERP_OLDER)
if (prev->m_AffineInterp != eAffineInterp::AFFINE_INTERP_COMPAT && prev->m_AffineInterp != eAffineInterp::AFFINE_INTERP_OLDER)
{
while (embers[i].m_Rotate < embers[i - 1].m_Rotate - 180)
embers[i].m_Rotate += 360;
while (it->m_Rotate < prev->m_Rotate - 180)
it->m_Rotate += 360;
while (embers[i].m_Rotate > embers[i - 1].m_Rotate + 180)
embers[i].m_Rotate -= 360;
while (it->m_Rotate > prev->m_Rotate + 180)
it->m_Rotate -= 360;
}
prev = it;
}
}
@ -373,14 +381,16 @@ public:
}
/// <summary>
/// Parse the specified file and place the results in the vector of embers passed in.
/// Parse the specified file and place the results in the container of embers passed in.
/// This will strip out ampersands because the Xml parser can't handle them.
/// </summary>
/// <param name="filename">Full path and filename</param>
/// <param name="embers">The newly constructed embers based on what was parsed</param>
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present. Default: true.</param>
/// <returns>True if there were no errors, else false.</returns>
bool Parse(const char* filename, vector<Ember<T>>& embers, bool useDefaults = true)
//template <typename T, typename Alloc, template <typename, typename> class C>
template <typename Alloc, template <typename, typename> class C>
bool Parse(const char* filename, C<Ember<T>, Alloc>& embers, bool useDefaults = true)
{
const char* loc = __FUNCTION__;
string buf;
@ -465,13 +475,14 @@ public:
private:
/// <summary>
/// Scan the file for ember nodes, and parse them out into the vector of embers.
/// Scan the file for ember nodes, and parse them out into the container of embers.
/// </summary>
/// <param name="curNode">The current node to parse</param>
/// <param name="parentFile">The full path and filename</param>
/// <param name="embers">The newly constructed embers based on what was parsed</param>
/// <param name="useDefaults">True to use defaults if they are not present in the file, else false to use invalid values as placeholders to indicate the values were not present.</param>
void ScanForEmberNodes(xmlNode* curNode, char* parentFile, vector<Ember<T>>& embers, bool useDefaults)
template <typename Alloc, template <typename, typename> class C>
void ScanForEmberNodes(xmlNode* curNode, char* parentFile, C<Ember<T>, Alloc>& embers, bool useDefaults)
{
bool parseEmberSuccess;
xmlNodePtr thisNode = nullptr;