--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

@ -144,7 +144,6 @@
<ClInclude Include="..\..\..\Source\Ember\Isaac.h" />
<ClInclude Include="..\..\..\Source\Ember\Timing.h" />
<ClInclude Include="..\..\..\Source\Ember\XmlToEmber.h" />
<ClInclude Include="resource1.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\Source\Ember\Affine2D.cpp" />

View File

@ -128,9 +128,6 @@
<ClInclude Include="..\..\..\Source\Ember\Variations07.h">
<Filter>Header Files\Variations</Filter>
</ClInclude>
<ClInclude Include="resource1.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\Source\Ember\DllMain.cpp">

View File

@ -158,6 +158,7 @@ xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms
<ClCompile Include="..\..\..\Source\Fractorium\FractoriumXaos.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\GLEmberController.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\GLWidget.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\LibraryTreeWidget.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\main.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\DoubleSpinBox.cpp" />
<ClCompile Include="..\..\..\Source\Fractorium\OptionsDialog.cpp" />
@ -198,6 +199,9 @@ xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms
<ClCompile Include="GeneratedFiles\Debug\moc_GLWidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_LibraryTreeWidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_OptionsDialog.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
@ -255,6 +259,9 @@ xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms
<ClCompile Include="GeneratedFiles\Release\moc_GLWidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_LibraryTreeWidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_OptionsDialog.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
@ -311,6 +318,16 @@ xcopy /F /Y /R /D "$(QTDIR)\plugins\platforms\qwindows.dll" "$(OutDir)\platforms
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
</CustomBuild>
<CustomBuild Include="..\..\..\Source\Fractorium\LibraryTreeWidget.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing LibraryTreeWidget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/LibraryTreeWidget.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(AMDAPPSDKROOT)\include" "-I$(CUDA_PATH)\include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing LibraryTreeWidget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fFractoriumPch.h" "-f../../../../../Source/Fractorium/LibraryTreeWidget.h" -DUNICODE -DWIN32 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_MULTIMEDIA_LIB -DQT_HELP_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_XML_LIB -D_MBCS "-I." "-I$(QTDIR)\include" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles" "-I$(ProjectDir)..\..\..\Fractorium\GeneratedFiles\ConfigurationName" "-I$(QTDIR)\..\qtmultimedia\include\QtMultimedia" "-I$(QTDIR)\..\qtmultimedia\include" "-I$(QTDIR)\..\qttools\include" "-I$(QTDIR)\..\qttools\include\QtHelp" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtXml" "-I.\GeneratedFiles" "-I$(ProjectDir)..\..\..\Source\Ember" "-I$(ProjectDir)..\..\..\Source\EmberCL" "-I$(ProjectDir)..\..\..\Source\EmberCommon" "-I$(ProjectDir)..\..\..\..\glm" "-I$(ProjectDir)..\..\..\..\tbb\include" "-I$(ProjectDir)..\..\..\..\libjpeg" "-I$(ProjectDir)..\..\..\..\libpng" "-I$(ProjectDir)..\..\..\..\libxml2\include" "-I$(AMDAPPSDKROOT)\include" "-I$(CUDA_PATH)\include" "-I.\GeneratedFiles\$(ConfigurationName)\."</Command>
</CustomBuild>
<ClInclude Include="..\..\..\Source\Fractorium\qcssparser.h" />
<ClInclude Include="..\..\..\Source\Fractorium\qfunctions.h" />
<CustomBuild Include="..\..\..\Source\Fractorium\QssTextEdit.h">

View File

@ -257,6 +257,15 @@
<ClCompile Include="GeneratedFiles\Release\moc_AboutDialog.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_LibraryTreeWidget.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_LibraryTreeWidget.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="..\..\..\Source\Fractorium\LibraryTreeWidget.cpp">
<Filter>Widgets</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GeneratedFiles\ui_Fractorium.h">
@ -393,6 +402,9 @@
<CustomBuild Include="..\..\..\Source\Fractorium\csshighlighter.h">
<Filter>Dialogs\Qss</Filter>
</CustomBuild>
<CustomBuild Include="..\..\..\Source\Fractorium\LibraryTreeWidget.h">
<Filter>Widgets</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\Source\Fractorium\Icons\Fractorium.ico" />

View File

@ -113,7 +113,8 @@ SOURCES += \
$$PRJ_SRC_DIR/QssDialog.cpp \
$$PRJ_SRC_DIR/QssTextEdit.cpp \
$$PRJ_SRC_DIR/SpinBox.cpp \
$$PRJ_SRC_DIR/VariationsDialog.cpp
$$PRJ_SRC_DIR/VariationsDialog.cpp \
$$PRJ_SRC_DIR/LibraryTreeWidget.cpp
HEADERS += \
$$SRC_COMMON_DIR/EmberCommon.h \
@ -148,7 +149,8 @@ HEADERS += \
$$PRJ_SRC_DIR/TableWidget.h \
$$PRJ_SRC_DIR/TwoButtonComboWidget.h \
$$PRJ_SRC_DIR/VariationsDialog.h \
$$PRJ_SRC_DIR/VariationTreeWidgetItem.h
$$PRJ_SRC_DIR/VariationTreeWidgetItem.h \
$$PRJ_SRC_DIR/LibraryTreeWidget.h
FORMS += \
$$PRJ_SRC_DIR/AboutDialog.ui \

View File

@ -158,7 +158,7 @@ win32 {
QMAKE_CXXFLAGS += -fPIC
QMAKE_CXXFLAGS += -fpermissive
QMAKE_CXXFLAGS += -pedantic
QMAKE_CXXFLAGS += -std=c++11
QMAKE_CXXFLAGS += -std=c++14
QMAKE_CXXFLAGS += -Wnon-virtual-dtor
QMAKE_CXXFLAGS += -Wshadow
QMAKE_CXXFLAGS += -Winit-self

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;

View File

@ -38,7 +38,7 @@ bool EmberAnimate(EmberOptions& opt)
const vector<pair<size_t, size_t>> devices = Devices(opt.Devices());
std::atomic<size_t> atomfTime;
vector<std::thread> threadVec;
unique_ptr<RenderProgress<T>> progress;
auto progress = make_unique<RenderProgress<T>>();
vector<unique_ptr<Renderer<T, float>>> renderers;
vector<string> errorReport;
std::recursive_mutex verboseCs;
@ -58,10 +58,7 @@ bool EmberAnimate(EmberOptions& opt)
}
if (opt.DoProgress())
{
progress = unique_ptr<RenderProgress<T>>(new RenderProgress<T>());
renderers[0]->Callback(progress.get());
}
cout << "Using OpenCL to render.\n";
@ -103,10 +100,7 @@ bool EmberAnimate(EmberOptions& opt)
}
if (opt.DoProgress())
{
progress = unique_ptr<RenderProgress<T>>(new RenderProgress<T>());
tempRenderer->Callback(progress.get());
}
if (opt.ThreadCount() == 0)
{
@ -304,7 +298,7 @@ bool EmberAnimate(EmberOptions& opt)
for (auto& r : renderers)
{
r->SetEmber(embers);
r->SetExternalEmbersPointer(&embers);//All will share a pointer to the original vector to conserve memory with large files. Ok because the vec doesn't get modified.
r->EarlyClip(opt.EarlyClip());
r->YAxisUp(opt.YAxisUp());
r->LockAccum(opt.LockAccum());
@ -390,12 +384,12 @@ bool EmberAnimate(EmberOptions& opt)
}
Interpolater<T>::Interpolate(embers, localTime, 0, centerEmber);//Get center flame.
emberToXml.Save(flameName, centerEmber, opt.PrintEditDepth(), true, opt.IntPalette(), opt.HexPalette(), true, false, false);
emberToXml.Save(flameName, centerEmber, opt.PrintEditDepth(), true, opt.HexPalette(), true, false, false);
centerEmber.Clear();
}
stats = renderer->Stats();
comments = renderer->ImageComments(stats, opt.PrintEditDepth(), opt.IntPalette(), opt.HexPalette());
comments = renderer->ImageComments(stats, opt.PrintEditDepth(), opt.HexPalette());
os.str("");
size_t iterCount = renderer->TotalIterCount(1);
os << comments.m_NumIters << " / " << iterCount << " (" << std::fixed << std::setprecision(2) << ((double(stats.m_Iters) / double(iterCount)) * 100) << "%)";

View File

@ -16,14 +16,6 @@ DEOpenCLKernelCreator::DEOpenCLKernelCreator(bool doublePrecision, bool nVidia)
{
m_DoublePrecision = doublePrecision;
m_NVidia = nVidia;
#ifdef ROW_ONLY_DE
m_LogScaleAssignDEEntryPoint = "LogScaleAssignDensityFilterKernel";
m_GaussianDEWithoutSsEntryPoint = "GaussianDEWithoutSsKernel";
m_GaussianDESsWithScfEntryPoint = "GaussianDESsWithScfKernel";
m_GaussianDESsWithoutScfEntryPoint = "GaussianDESsWithoutScfKernel";
m_GaussianDEWithoutSsNoCacheEntryPoint = "GaussianDEWithoutSsNoCacheKernel";
m_GaussianDESsWithScfNoCacheEntryPoint = "GaussianDESsWithScfNoCacheKernel";
m_GaussianDESsWithoutScfNoCacheEntryPoint = "GaussianDESsWithoutScfNoCacheKernel";
m_LogScaleAssignDEKernel = CreateLogScaleAssignDEKernelString();
m_GaussianDEWithoutSsKernel = CreateGaussianDEKernel(1);
m_GaussianDESsWithScfKernel = CreateGaussianDEKernel(2);
@ -31,22 +23,6 @@ DEOpenCLKernelCreator::DEOpenCLKernelCreator(bool doublePrecision, bool nVidia)
m_GaussianDEWithoutSsNoCacheKernel = CreateGaussianDEKernelNoLocalCache(1);
m_GaussianDESsWithScfNoCacheKernel = CreateGaussianDEKernelNoLocalCache(2);
m_GaussianDESsWithoutScfNoCacheKernel = CreateGaussianDEKernelNoLocalCache(3);
#else
m_LogScaleAssignDEEntryPoint = "LogScaleAssignDensityFilterKernel";
m_GaussianDEWithoutSsEntryPoint = "GaussianDEWithoutSsKernel";
m_GaussianDESsWithScfEntryPoint = "GaussianDESsWithScfKernel";
m_GaussianDESsWithoutScfEntryPoint = "GaussianDESsWithoutScfKernel";
m_GaussianDEWithoutSsNoCacheEntryPoint = "GaussianDEWithoutSsNoCacheKernel";
m_GaussianDESsWithScfNoCacheEntryPoint = "GaussianDESsWithScfNoCacheKernel";
m_GaussianDESsWithoutScfNoCacheEntryPoint = "GaussianDESsWithoutScfNoCacheKernel";
m_LogScaleAssignDEKernel = CreateLogScaleAssignDEKernelString();
m_GaussianDEWithoutSsKernel = CreateGaussianDEKernel(1);
m_GaussianDESsWithScfKernel = CreateGaussianDEKernel(2);
m_GaussianDESsWithoutScfKernel = CreateGaussianDEKernel(3);
m_GaussianDEWithoutSsNoCacheKernel = CreateGaussianDEKernelNoLocalCache(1);
m_GaussianDESsWithScfNoCacheKernel = CreateGaussianDEKernelNoLocalCache(2);
m_GaussianDESsWithoutScfNoCacheKernel = CreateGaussianDEKernelNoLocalCache(3);
#endif
}
/// <summary>
@ -64,8 +40,6 @@ const string& DEOpenCLKernelCreator::LogScaleAssignDEEntryPoint() const { return
/// <returns>The kernel source</returns>
const string& DEOpenCLKernelCreator::GaussianDEKernel(size_t ss, uint filterWidth) const
{
#ifndef ROW_ONLY_DE
if (filterWidth > MaxDEFilterSize())
{
if (ss > 1)
@ -79,7 +53,6 @@ const string& DEOpenCLKernelCreator::GaussianDEKernel(size_t ss, uint filterWidt
return m_GaussianDEWithoutSsNoCacheKernel;//SS 1;
}
else//Use cache.
#endif
{
if (ss > 1)
{
@ -101,8 +74,6 @@ const string& DEOpenCLKernelCreator::GaussianDEKernel(size_t ss, uint filterWidt
/// <returns>The name of the density estimation filtering entry point kernel function</returns>
const string& DEOpenCLKernelCreator::GaussianDEEntryPoint(size_t ss, uint filterWidth) const
{
#ifndef ROW_ONLY_DE
if (filterWidth > MaxDEFilterSize())
{
if (ss > 1)
@ -116,7 +87,6 @@ const string& DEOpenCLKernelCreator::GaussianDEEntryPoint(size_t ss, uint filter
return m_GaussianDEWithoutSsNoCacheEntryPoint;
}
else
#endif
{
if (ss > 1)
{
@ -206,210 +176,6 @@ string DEOpenCLKernelCreator::CreateLogScaleAssignDEKernelString()
return os.str();
}
#ifdef ROW_ONLY_DE
string DEOpenCLKernelCreator::CreateGaussianDEKernel(size_t ss)
{
bool doSS = ss > 1;
bool doScf = !(ss & 1);
ostringstream os;
os <<
ConstantDefinesString(m_DoublePrecision) <<
DensityFilterCLStructString <<
UnionCLStructString <<
"__kernel void " << GaussianDEEntryPoint(ss, MaxDEFilterSize()) << "(\n" <<
" const __global real4_bucket* histogram,\n"
" __global real4reals_bucket* accumulator,\n"
" __constant DensityFilterCL* densityFilter,\n"
" const __global real_bucket_t* filterCoefs,\n"
" const __global real_bucket_t* filterWidths,\n"
" const __global uint* coefIndices,\n"
" const uint chunkSizeW,\n"
" const uint chunkSizeH,\n"
" const uint colChunkPass,\n"
" const uint rowChunkPass\n"
"\t)\n"
"{\n"
" uint rowsToProcess = 32;\n"//Rows to process.
"\n"
" if (((((BLOCK_ID_X * chunkSizeW) + colChunkPass) * BLOCK_SIZE_X) + THREAD_ID_X >= densityFilter->m_SuperRasW) ||\n"
" ((((BLOCK_ID_Y * chunkSizeH) + rowChunkPass) * rowsToProcess) + THREAD_ID_Y >= densityFilter->m_SuperRasH))\n"
" return;\n"
"\n";
if (doSS)
{
os <<
" uint ss = (uint)floor((real_bucket_t)densityFilter->m_Supersample / 2.0);\n"
" int densityBoxLeftX;\n"
" int densityBoxRightX;\n"
" int densityBoxTopY;\n"
" int densityBoxBottomY;\n"
"\n";
if (doScf)
os <<
" real_bucket_t scfact = pow(densityFilter->m_Supersample / (densityFilter->m_Supersample + (real_bucket_t)1.0), (real_bucket_t)2.0);\n";
}
os <<
" uint fullTempBoxWidth;\n"
" uint leftBound, rightBound, topBound, botBound;\n"
" uint blockHistStartRow, blockHistEndRow, histCol;\n"
" uint blockHistStartCol, boxReadStartCol, boxReadEndCol;\n"
" uint accumWriteStartCol, colsToWrite, colOffset, colsToWriteOffset;\n"
" int histRow, filterRow, accumWriteOffset;\n"
"\n"
" fullTempBoxWidth = BLOCK_SIZE_X + (densityFilter->m_FilterWidth * 2);\n"
//Compute the bounds of the area to be sampled, which is just the ends minus the super sample minus 1.
" leftBound = densityFilter->m_Supersample - 1;\n"
" rightBound = densityFilter->m_SuperRasW - (densityFilter->m_Supersample - 1);\n"
" topBound = densityFilter->m_Supersample - 1;\n"
" botBound = densityFilter->m_SuperRasH - (densityFilter->m_Supersample - 1);\n"
"\n"
//Start and end values are the indices in the histogram read from
//and written to in the accumulator. They are not the indices for the local block of data.
//Before computing local offsets, compute the global offsets first to determine if any rows or cols fall outside of the bounds.
" blockHistStartRow = min(botBound, topBound + (((BLOCK_ID_Y * chunkSizeH) + rowChunkPass) * rowsToProcess));\n"//The first histogram row this block will process.
" blockHistEndRow = min(botBound, blockHistStartRow + rowsToProcess);\n"//The last histogram row this block will process, clamped to the last row.
" blockHistStartCol = min(rightBound, leftBound + (((BLOCK_ID_X * chunkSizeW) + colChunkPass) * BLOCK_SIZE_X));\n"//The first histogram column this block will process.
" boxReadStartCol = densityFilter->m_FilterWidth - min(densityFilter->m_FilterWidth, blockHistStartCol);\n"//The first box col this block will read from when copying to the accumulator.
" boxReadEndCol = densityFilter->m_FilterWidth + min(densityFilter->m_FilterWidth + BLOCK_SIZE_X, densityFilter->m_SuperRasW - blockHistStartCol);\n"//The last box col this block will read from when copying to the accumulator.
"\n"
//Last, the indices in the global accumulator that the local bounds will be writing to.
" accumWriteStartCol = blockHistStartCol - min(densityFilter->m_FilterWidth, blockHistStartCol);\n"//The first column in the accumulator this block will write to.
" colsToWrite = ceil((real_bucket_t)(boxReadEndCol - boxReadStartCol) / (real_bucket_t)BLOCK_SIZE_X);\n"//Elements per thread to be written to the accumulator.
" histCol = blockHistStartCol + THREAD_ID_X;\n"//The histogram column this individual thread will be reading from.
"\n"
" if (histCol >= rightBound)\n"
" return;\n"
"\n"
//Compute the col position in this local box to serve as the center position
//from which filter application offsets are computed.
//These are the local indices for the local data that are temporarily accumulated to before
//writing out to the global accumulator.
" uint boxCol = densityFilter->m_FilterWidth + THREAD_ID_X;\n"
" uint colsToZeroOffset, colsToZero = ceil((real_bucket_t)fullTempBoxWidth / (real_bucket_t)(BLOCK_SIZE_X));\n"//Usually is 2.
" int i, j, k, jmin, jmax;\n"
" uint filterSelectInt, filterCoefIndex;\n"
" real_bucket_t cacheLog;\n"
" real_bucket_t filterSelect;\n"
" real4_bucket bucket;\n"
;
os << " __local real4reals_bucket filterBox[192];\n";//Must be >= fullTempBoxWidth.
os <<
"\n"
" colsToZeroOffset = colsToZero * THREAD_ID_X;\n"
" colsToWriteOffset = colsToWrite * THREAD_ID_X;\n"
" k = (int)densityFilter->m_FilterWidth;\n"//Need a signed int to use below, really is filter width, but reusing a variable to save space.
"\n"
" for (histRow = blockHistStartRow; histRow < blockHistEndRow; histRow++)\n"//Process pixels by row, for 32 rows.
" {\n"
" bucket = histogram[(histRow * densityFilter->m_SuperRasW) + histCol];\n"
"\n"
" if (bucket.w != 0)\n"
" cacheLog = (densityFilter->m_K1 * log(1.0 + bucket.w * densityFilter->m_K2)) / bucket.w;\n"
"\n";
if (doSS)
{
os <<
" filterSelect = 0;\n"
" densityBoxLeftX = histCol - min(histCol, ss);\n"
" densityBoxRightX = histCol + min(ss, (densityFilter->m_SuperRasW - histCol) - 1);\n"
" densityBoxTopY = histRow - min((uint)histRow, ss);\n"
" densityBoxBottomY = histRow + min(ss, (densityFilter->m_SuperRasH - histRow) - 1);\n"
"\n"
" for (j = densityBoxTopY; j <= densityBoxBottomY; j++)\n"
" {\n"
" for (i = densityBoxLeftX; i <= densityBoxRightX; i++)\n"
" {\n"
" filterSelect += histogram[(j * densityFilter->m_SuperRasW) + i].w;\n"
" }\n"
" }\n"
"\n";
if (doScf)
os << " filterSelect *= scfact;\n";
}
else
{
os
<< " filterSelect = bucket.w;\n";
}
os <<
"\n"
" if (filterSelect > densityFilter->m_MaxFilteredCounts)\n"
" filterSelectInt = densityFilter->m_MaxFilterIndex;\n"
" else if (filterSelect <= DE_THRESH)\n"
" filterSelectInt = (int)ceil(filterSelect) - 1;\n"
" else if (filterSelect != 0)\n"
" filterSelectInt = (int)DE_THRESH + (int)floor(pow((real_bucket_t)(filterSelect - DE_THRESH), densityFilter->m_Curve));\n"
" else\n"
" filterSelectInt = 0;\n"
"\n"
" if (filterSelectInt > densityFilter->m_MaxFilterIndex)\n"
" filterSelectInt = densityFilter->m_MaxFilterIndex;\n"
"\n"
" filterCoefIndex = filterSelectInt * densityFilter->m_KernelSize;\n"
"\n"
//With this new method, only accumulate to the temp local buffer first. Write to the final accumulator last.
//For each loop through, note that there is a local memory barrier call inside of each call to AddToAccumNoCheck().
//If this isn't done, pixel errors occurr and even an out of resources error occurrs because too many writes are done to the same place in memory at once.
" jmin = min(k, histRow);\n"
" jmax = (int)min((densityFilter->m_SuperRasH - 1) - histRow, densityFilter->m_FilterWidth);\n"
"\n"
" for (j = -jmin; j <= jmax; j++)\n"
" {\n"
" for (i = 0; i < colsToZero && (colsToZeroOffset + i) < fullTempBoxWidth; i++)\n"//Each thread zeroizes a few columns.
" {\n"
" filterBox[colsToZeroOffset + i].m_Real4 = 0;\n"
" }\n"
"\n"
" barrier(CLK_LOCAL_MEM_FENCE);\n"
"\n"
" if (bucket.w != 0)\n"
" {\n"
" filterRow = abs(j) * (densityFilter->m_FilterWidth + 1);\n"
"\n"
" for (i = -k; i <= k; i++)\n"
" {\n"
" filterSelectInt = filterCoefIndex + coefIndices[filterRow + abs(i)];\n"//Really is filterCoeffIndexPlusOffset, but reusing a variable to save space.
" filterBox[i + boxCol].m_Real4 += (bucket * (filterCoefs[filterSelectInt] * cacheLog));\n"
" }\n"
" }\n"
"\n"
" barrier(CLK_LOCAL_MEM_FENCE);\n"
"\n"
//At this point, all threads in this block have applied the filter to their surrounding pixels and stored the results in the temp local box.
//Add the cells of it that are in bounds to the global accumulator.
//Compute offsets in local box to read from, and offsets into global accumulator to write to.
//Use a method here that is similar to the zeroization above: Each thread (column) in the first row iterates through all of the
//rows and adds a few columns to the accumulator.
//" if (THREAD_ID_X == 0)\n"
//" {\n"
//" for (int kk = boxReadStartCol, i = 0; kk < boxReadEndCol; kk++, i++)\n"//Each thread writes a few columns.//Could do away with kk//TODO//OPT
//" {\n"
//" accumulator[((histRow + j) * densityFilter->m_SuperRasW) + (accumWriteStartCol + i)].m_Real4 += filterBox[kk].m_Real4;\n"
//" }\n"
//" }\n"
" accumWriteOffset = ((histRow + j) * densityFilter->m_SuperRasW) + accumWriteStartCol;\n"
"\n"
" for (i = 0; i < colsToWrite; i++)\n"//Each thread writes a few columns.
" {\n"
" colOffset = colsToWriteOffset + i;\n"
"\n"
" if (boxReadStartCol + colOffset < boxReadEndCol)\n"
" accumulator[accumWriteOffset + colOffset].m_Real4 += filterBox[boxReadStartCol + colOffset].m_Real4;\n"
" }\n"
" }\n"//for() filter rows.
" barrier(CLK_GLOBAL_MEM_FENCE);\n"
" }\n"//for() histogram rows.
"}\n";
return os.str();
}
#else
/// <summary>
/// Create the gaussian density filtering kernel string.
/// 6 different methods of processing were tried before settling on this final and fastest 7th one.
@ -660,7 +426,6 @@ string DEOpenCLKernelCreator::CreateGaussianDEKernel(size_t ss)
"}\n";
return os.str();
}
#endif
/// <summary>
/// Create the gaussian density filtering kernel string, but use no local cache and perform

View File

@ -8,8 +8,6 @@
/// DEOpenCLKernelCreator class.
/// </summary>
//#define ROW_ONLY_DE 1
namespace EmberCLns
{
/// <summary>
@ -51,25 +49,25 @@ private:
string CreateGaussianDEKernelNoLocalCache(size_t ss);
string m_LogScaleAssignDEKernel;
string m_LogScaleAssignDEEntryPoint;
string m_LogScaleAssignDEEntryPoint = "LogScaleAssignDensityFilterKernel";
string m_GaussianDEWithoutSsKernel;
string m_GaussianDEWithoutSsEntryPoint;
string m_GaussianDEWithoutSsEntryPoint = "GaussianDEWithoutSsKernel";
string m_GaussianDESsWithScfKernel;
string m_GaussianDESsWithScfEntryPoint;
string m_GaussianDESsWithScfEntryPoint = "GaussianDESsWithScfKernel";
string m_GaussianDESsWithoutScfKernel;
string m_GaussianDESsWithoutScfEntryPoint;
string m_GaussianDESsWithoutScfEntryPoint = "GaussianDESsWithoutScfKernel";
string m_GaussianDEWithoutSsNoCacheKernel;
string m_GaussianDEWithoutSsNoCacheEntryPoint;
string m_GaussianDEWithoutSsNoCacheEntryPoint = "GaussianDEWithoutSsNoCacheKernel";
string m_GaussianDESsWithScfNoCacheKernel;
string m_GaussianDESsWithScfNoCacheEntryPoint;
string m_GaussianDESsWithScfNoCacheEntryPoint = "GaussianDESsWithScfNoCacheKernel";
string m_GaussianDESsWithoutScfNoCacheKernel;
string m_GaussianDESsWithoutScfNoCacheEntryPoint;
string m_GaussianDESsWithoutScfNoCacheEntryPoint = "GaussianDESsWithoutScfNoCacheKernel";
bool m_DoublePrecision;
bool m_NVidia;

View File

@ -10,22 +10,14 @@ namespace EmberCLns
FinalAccumOpenCLKernelCreator::FinalAccumOpenCLKernelCreator(bool doublePrecision)
{
m_DoublePrecision = doublePrecision;
m_GammaCorrectionWithAlphaCalcEntryPoint = "GammaCorrectionWithAlphaCalcKernel";
m_GammaCorrectionWithoutAlphaCalcEntryPoint = "GammaCorrectionWithoutAlphaCalcKernel";
m_GammaCorrectionWithAlphaCalcKernel = CreateGammaCorrectionKernelString(true);
m_GammaCorrectionWithoutAlphaCalcKernel = CreateGammaCorrectionKernelString(false);
m_FinalAccumEarlyClipEntryPoint = "FinalAccumEarlyClipKernel";
m_FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumKernel";
m_FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumKernel";
m_GammaCorrectionWithAlphaCalcKernel = CreateGammaCorrectionKernelString(true);
m_GammaCorrectionWithoutAlphaCalcKernel = CreateGammaCorrectionKernelString(false);
m_FinalAccumEarlyClipKernel = CreateFinalAccumKernelString(true, false, false);
m_FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumKernel = CreateFinalAccumKernelString(true, true, true);
m_FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumKernel = CreateFinalAccumKernelString(true, false, true);
m_FinalAccumLateClipEntryPoint = "FinalAccumLateClipKernel";
m_FinalAccumLateClipWithAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumLateClipWithAlphaCalcWithAlphaAccumKernel";
m_FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumKernel";
m_FinalAccumLateClipKernel = CreateFinalAccumKernelString(false, false, false);
m_FinalAccumLateClipWithAlphaCalcWithAlphaAccumKernel = CreateFinalAccumKernelString(false, true, true);
m_FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumKernel = CreateFinalAccumKernelString(false, false, true);
m_FinalAccumLateClipKernel = CreateFinalAccumKernelString(false, false, false);
m_FinalAccumLateClipWithAlphaCalcWithAlphaAccumKernel = CreateFinalAccumKernelString(false, true, true);
m_FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumKernel = CreateFinalAccumKernelString(false, false, true);
}
/// <summary>

View File

@ -58,24 +58,24 @@ private:
string CreateCalcNewRgbFunctionString(bool globalBucket);
string m_GammaCorrectionWithAlphaCalcKernel;
string m_GammaCorrectionWithAlphaCalcEntryPoint;
string m_GammaCorrectionWithAlphaCalcEntryPoint = "GammaCorrectionWithAlphaCalcKernel";
string m_GammaCorrectionWithoutAlphaCalcKernel;
string m_GammaCorrectionWithoutAlphaCalcEntryPoint;
string m_GammaCorrectionWithoutAlphaCalcEntryPoint = "GammaCorrectionWithoutAlphaCalcKernel";
string m_FinalAccumEarlyClipKernel;//False, false.
string m_FinalAccumEarlyClipEntryPoint;
string m_FinalAccumEarlyClipEntryPoint = "FinalAccumEarlyClipKernel";
string m_FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumKernel;//True, true.
string m_FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumEntryPoint;
string m_FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumEarlyClipWithAlphaCalcWithAlphaAccumKernel";
string m_FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumKernel;//False, true.
string m_FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumEntryPoint;
string m_FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumEarlyClipWithoutAlphaCalcWithAlphaAccumKernel";
string m_FinalAccumLateClipKernel;//False, false.
string m_FinalAccumLateClipEntryPoint;
string m_FinalAccumLateClipEntryPoint = "FinalAccumLateClipKernel";
string m_FinalAccumLateClipWithAlphaCalcWithAlphaAccumKernel;//True, true.
string m_FinalAccumLateClipWithAlphaCalcWithAlphaAccumEntryPoint;
string m_FinalAccumLateClipWithAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumLateClipWithAlphaCalcWithAlphaAccumKernel";
string m_FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumKernel;//False, true.
string m_FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumEntryPoint;
string m_FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumEntryPoint = "FinalAccumLateClipWithoutAlphaCalcWithAlphaAccumKernel";
string m_Empty;
bool m_DoublePrecision;

View File

@ -12,9 +12,6 @@ namespace EmberCLns
template <typename T>
IterOpenCLKernelCreator<T>::IterOpenCLKernelCreator()
{
m_IterEntryPoint = "IterateKernel";
m_ZeroizeEntryPoint = "ZeroizeKernel";
m_SumHistEntryPoint = "SumHisteKernel";
m_ZeroizeKernel = CreateZeroizeKernelString();
m_SumHistKernel = CreateSumHistKernelString();
}
@ -23,11 +20,11 @@ IterOpenCLKernelCreator<T>::IterOpenCLKernelCreator()
/// Accessors.
/// </summary>
template <typename T> const string& IterOpenCLKernelCreator<T>::ZeroizeKernel() const { return m_ZeroizeKernel; }
template <typename T> const string& IterOpenCLKernelCreator<T>::ZeroizeKernel() const { return m_ZeroizeKernel; }
template <typename T> const string& IterOpenCLKernelCreator<T>::ZeroizeEntryPoint() const { return m_ZeroizeEntryPoint; }
template <typename T> const string& IterOpenCLKernelCreator<T>::SumHistKernel() const { return m_SumHistKernel; }
template <typename T> const string& IterOpenCLKernelCreator<T>::SumHistKernel() const { return m_SumHistKernel; }
template <typename T> const string& IterOpenCLKernelCreator<T>::SumHistEntryPoint() const { return m_SumHistEntryPoint; }
template <typename T> const string& IterOpenCLKernelCreator<T>::IterEntryPoint() const { return m_IterEntryPoint; }
template <typename T> const string& IterOpenCLKernelCreator<T>::IterEntryPoint() const { return m_IterEntryPoint; }
/// <summary>
/// Create the iteration kernel string using the Cuburn method.

View File

@ -43,11 +43,11 @@ private:
string CreateSumHistKernelString() const;
string CreateProjectionString(const Ember<T>& ember) const;
string m_IterEntryPoint;
string m_IterEntryPoint = "IterateKernel";
string m_ZeroizeKernel;
string m_ZeroizeEntryPoint;
string m_ZeroizeEntryPoint = "ZeroizeKernel";
string m_SumHistKernel;
string m_SumHistEntryPoint;
string m_SumHistEntryPoint = "SumHisteKernel";
FunctionMapper m_FunctionMapper;
};

View File

@ -10,17 +10,11 @@ namespace EmberCLns
/// </summary>
OpenCLWrapper::OpenCLWrapper()
{
m_Init = false;
m_Shared = false;
m_PlatformIndex = 0;
m_DeviceIndex = 0;
m_LocalMemSize = 0;
//Pre-allocate some space to avoid temporary copying.
m_Programs.reserve(4);
m_Buffers.reserve(4);
m_Images.reserve(4);
m_GLImages.reserve(4);
m_Info = OpenCLInfo::Instance();
}
/// <summary>

View File

@ -184,18 +184,18 @@ public:
private:
bool CreateSPK(const string& name, const string& program, const string& entryPoint, Spk& spk, bool doublePrecision);
bool m_Init;
bool m_Shared;
size_t m_PlatformIndex;
size_t m_DeviceIndex;
size_t m_LocalMemSize;
bool m_Init = false;
bool m_Shared = false;
size_t m_PlatformIndex = 0;
size_t m_DeviceIndex = 0;
size_t m_LocalMemSize = 0;
size_t m_GlobalMemSize;
size_t m_MaxAllocSize;
cl::Platform m_Platform;
cl::Context m_Context;
cl::Device m_Device;
cl::CommandQueue m_Queue;
shared_ptr<OpenCLInfo> m_Info;
shared_ptr<OpenCLInfo> m_Info = OpenCLInfo::Instance();
std::vector<cl::Device> m_DeviceVec;
std::vector<Spk> m_Programs;
std::vector<NamedBuffer> m_Buffers;

View File

@ -76,14 +76,6 @@ void RendererCL<T, bucketT>::Init()
m_FinalFormat.image_channel_data_type = CL_UNORM_INT8;//Change if this ever supports 2BPC outputs for PNG.
}
/// <summary>
/// Virtual destructor.
/// </summary>
template <typename T, typename bucketT>
RendererCL<T, bucketT>::~RendererCL()
{
}
/// <summary>
/// Non-virtual member functions for OpenCL specific tasks.
/// </summary>

View File

@ -95,7 +95,9 @@ class EMBERCL_API RendererCL : public Renderer<T, bucketT>, public RendererCLBas
public:
RendererCL(const vector<pair<size_t, size_t>>& devices, bool shared = false, GLuint outputTexID = 0);
~RendererCL();
RendererCL(const RendererCL<T, bucketT>& renderer) = delete;
RendererCL<T, bucketT>& operator = (const RendererCL<T, bucketT>& renderer) = delete;
virtual ~RendererCL() = default;
//Non-virtual member functions for OpenCL specific tasks.
bool Init(const vector<pair<size_t, size_t>>& devices, bool shared, GLuint outputTexID);

View File

@ -20,10 +20,9 @@ public:
/// <summary>
/// Constructor that initializes the state to zero.
/// </summary>
RenderProgress()
{
Clear();
}
RenderProgress() = default;
RenderProgress(RenderProgress<T>& progress) = delete;
~RenderProgress() = default;
/// <summary>
/// The progress function which will be called from inside the renderer.
@ -33,7 +32,7 @@ public:
/// <param name="fraction">The progress fraction from 0-100</param>
/// <param name="stage">The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.</param>
/// <param name="etaMs">The estimated milliseconds to completion of the current stage</param>
/// <returns>1 since this is intended to run in an environment where the render runs to completion, unlike interactive rendering.</returns>
/// <returns>The value of m_Running, which is always true since this is intended to run in an environment where the render runs to completion, unlike interactive rendering.</returns>
virtual int ProgressFunc(Ember<T>& ember, void* foo, double fraction, int stage, double etaMs)
{
if (stage == 0 || stage == 1)
@ -51,7 +50,7 @@ public:
}
m_LastStage = stage;
return 1;
return m_Running;
}
/// <summary>
@ -59,15 +58,25 @@ public:
/// </summary>
void Clear()
{
m_Running = 1;
m_LastStage = 0;
m_LastLength = 0;
m_SS.clear();
m_S.clear();
}
/// <summary>
/// Stop this instance.
/// </summary>
void Stop()
{
m_Running = 0;
}
private:
int m_LastStage;
int m_LastLength;
int m_Running = 1;
int m_LastStage = 0;
int m_LastLength = 0;
stringstream m_SS;
string m_S;
Timing t;
@ -286,7 +295,7 @@ static Renderer<T, float>* CreateRenderer(eRendererType renderType, const vector
if (renderType == eRendererType::OPENCL_RENDERER && !devices.empty())
{
s = "OpenCL";
renderer = unique_ptr<Renderer<T, float>>(new RendererCL<T, float>(devices, shared, texId));
renderer = unique_ptr<Renderer<T, float>>(new RendererCL<T, float>(devices, shared, texId));//Can't use make_unique here.
if (!renderer.get() || !renderer->Ok())
{
@ -294,13 +303,13 @@ static Renderer<T, float>* CreateRenderer(eRendererType renderType, const vector
errorReport.AddToReport(renderer->ErrorReport());
errorReport.AddToReport("Error initializing OpenCL renderer, using CPU renderer instead.");
renderer = unique_ptr<Renderer<T, float>>(new Renderer<T, float>());
renderer = make_unique<Renderer<T, float>>();
}
}
else
{
s = "CPU";
renderer = unique_ptr<Renderer<T, float>>(new Renderer<T, float>());
renderer = make_unique<Renderer<T, float>>();
}
}
catch (const std::exception& e)
@ -343,7 +352,7 @@ static vector<unique_ptr<Renderer<T, float>>> CreateRenderers(eRendererType rend
for (size_t i = 0; i < devices.size(); i++)
{
vector<pair<size_t, size_t>> tempDevices{ devices[i] };
auto renderer = unique_ptr<Renderer<T, float>>(new RendererCL<T, float>(tempDevices, !i ? shared : false, texId));
auto renderer = unique_ptr<Renderer<T, float>>(new RendererCL<T, float>(tempDevices, !i ? shared : false, texId));//Can't use make_unique here.
if (!renderer.get() || !renderer->Ok())
{

View File

@ -308,7 +308,7 @@ public:
INITBOOLOPTION(Verbose, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_VERBOSE, _T("--verbose"), false, SO_NONE, "\t--verbose Verbose output.\n"));
INITBOOLOPTION(Debug, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_DEBUG, _T("--debug"), false, SO_NONE, "\t--debug Debug output.\n"));
INITBOOLOPTION(DumpArgs, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_DUMP_ARGS, _T("--dumpargs"), false, SO_NONE, "\t--dumpargs Print all arguments entered from either the command line or environment variables.\n"));
INITBOOLOPTION(DoProgress, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PROGRESS, _T("--progress"), false, SO_NONE, "\t--progress Display progress. This will slow down processing by about 10%%.\n"));
INITBOOLOPTION(DoProgress, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PROGRESS, _T("--progress"), false, SO_NONE, "\t--progress Display progress. This will slow down processing by about 10%.\n"));
INITBOOLOPTION(OpenCLInfo, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_DUMP_OPENCL_INFO, _T("--openclinfo"), false, SO_NONE, "\t--openclinfo Display platforms and devices for OpenCL.\n"));
INITBOOLOPTION(AllVars, Eob(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_ALL_VARS, _T("--allvars"), false, SO_NONE, "\t--allvars Display the names of all supported variations.\n"));
INITBOOLOPTION(RegVars, Eob(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_REG_VARS, _T("--regvars"), false, SO_NONE, "\t--regvars Display the names of all supported regular variations.\n"));
@ -319,15 +319,14 @@ public:
INITBOOLOPTION(EarlyClip, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_EARLYCLIP, _T("--earlyclip"), false, SO_NONE, "\t--earlyclip Perform clipping of RGB values before spatial filtering for better antialiasing and resizing [default: false].\n"));
INITBOOLOPTION(YAxisUp, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_POS_Y_UP, _T("--yaxisup"), false, SO_NONE, "\t--yaxisup Orient the image with the positive y axis pointing up [default: false].\n"));
INITBOOLOPTION(Transparency, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_TRANSPARENCY, _T("--transparency"), false, SO_NONE, "\t--transparency Include alpha channel in final output [default: false except for PNG].\n"));
INITBOOLOPTION(NameEnable, Eob(eOptionUse::OPT_USE_RENDER, eOptionIDs::OPT_NAME_ENABLE, _T("--name_enable"), false, SO_NONE, "\t--name_enable Use the name attribute contained in the xml as the output filename [default: false].\n"));
INITBOOLOPTION(IntPalette, Eob(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_INT_PALETTE, _T("--intpalette"), false, SO_NONE, "\t--intpalette Force palette RGB values to be integers [default: false (float)].\n"));
INITBOOLOPTION(NameEnable, Eob(eOptionUse::OPT_USE_RENDER, eOptionIDs::OPT_NAME_ENABLE, _T("--name_enable"), false, SO_NONE, "\t--name_enable Use the name attribute contained in the Xml as the output filename [default: false].\n"));
INITBOOLOPTION(HexPalette, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_HEX_PALETTE, _T("--hex_palette"), true, SO_OPT, "\t--hex_palette Force palette RGB values to be hex [default: true].\n"));
INITBOOLOPTION(InsertPalette, Eob(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_INSERT_PALETTE, _T("--insert_palette"), false, SO_NONE, "\t--insert_palette Insert the palette into the image for debugging purposes [default: false].\n"));
INITBOOLOPTION(JpegComments, Eob(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_JPEG_COMMENTS, _T("--enable_jpeg_comments"), true, SO_OPT, "\t--enable_jpeg_comments Enables comments in the jpeg header [default: true].\n"));
INITBOOLOPTION(PngComments, Eob(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_PNG_COMMENTS, _T("--enable_png_comments"), true, SO_OPT, "\t--enable_png_comments Enables comments in the png header [default: true].\n"));
INITBOOLOPTION(WriteGenome, Eob(eOptionUse::OPT_USE_ANIMATE, eOptionIDs::OPT_WRITE_GENOME, _T("--write_genome"), false, SO_NONE, "\t--write_genome Write out flame associated with center of motion blur window [default: false].\n"));
INITBOOLOPTION(ThreadedWrite, Eob(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_THREADED_WRITE, _T("--threaded_write"), true, SO_OPT, "\t--threaded_write Use a separate thread to write images to disk. This gives better performance, but doubles the memory required for the final output buffer. [default: true].\n"));
INITBOOLOPTION(Enclosed, Eob(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_ENCLOSED, _T("--enclosed"), true, SO_OPT, "\t--enclosed Use enclosing XML tags [default: true].\n"));
INITBOOLOPTION(Enclosed, Eob(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_ENCLOSED, _T("--enclosed"), true, SO_OPT, "\t--enclosed Use enclosing Xml tags [default: true].\n"));
INITBOOLOPTION(NoEdits, Eob(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_NO_EDITS, _T("--noedits"), false, SO_NONE, "\t--noedits Exclude edit tags when writing Xml [default: false].\n"));
INITBOOLOPTION(UnsmoothEdge, Eob(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_UNSMOOTH_EDGE, _T("--unsmoother"), false, SO_NONE, "\t--unsmoother Do not use smooth blending for sheep edges [default: false].\n"));
INITBOOLOPTION(LockAccum, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_LOCK_ACCUM, _T("--lock_accum"), false, SO_NONE, "\t--lock_accum Lock threads when accumulating to the histogram using the CPU. This will drop performance to that of single threading [default: false].\n"));
@ -346,13 +345,13 @@ public:
INITUINTOPTION(ThreadCount, Eou(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_NTHREADS, _T("--nthreads"), 0, SO_REQ_SEP, "\t--nthreads=<val> The number of threads to use [default: use all available cores].\n"));
INITUINTOPTION(Strips, Eou(eOptionUse::OPT_USE_RENDER, eOptionIDs::OPT_STRIPS, _T("--nstrips"), 1, SO_REQ_SEP, "\t--nstrips=<val> The number of fractions to split a single render frame into. Useful for print size renders or low memory systems [default: 1].\n"));
INITUINTOPTION(Supersample, Eou(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_SUPERSAMPLE, _T("--supersample"), 0, SO_REQ_SEP, "\t--supersample=<val> The supersample value used to override the one specified in the file [default: 0 (use value from file)].\n"));
INITUINTOPTION(BitsPerChannel, Eou(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_BPC, _T("--bpc"), 8, SO_REQ_SEP, "\t--bpc=<val> Bits per channel. 8 or 16 for PNG, 8 for all others [default: 8].\n"));
INITUINTOPTION(BitsPerChannel, Eou(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_BPC, _T("--bpc"), 8, SO_REQ_SEP, "\t--bpc=<val> Bits per channel. 8 or 16 for PNG, 8 for all others, always 8 with OpenCL [default: 8].\n"));
INITUINTOPTION(SubBatchSize, Eou(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_SBS, _T("--sub_batch_size"), DEFAULT_SBS, SO_REQ_SEP, "\t--sub_batch_size=<val> The chunk size that iterating will be broken into [default: 10k].\n"));
INITUINTOPTION(Bits, Eou(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_BITS, _T("--bits"), 33, SO_REQ_SEP, "\t--bits=<val> Determines the types used for the histogram and accumulator [default: 33].\n"
"\t\t\t\t\t32: Histogram: float, Accumulator: float.\n"
"\t\t\t\t\t33: Histogram: float, Accumulator: float.\n"//This differs from the original which used an int hist for bits 33.
"\t\t\t\t\t64: Histogram: double, Accumulator: double.\n"));
INITUINTOPTION(PrintEditDepth, Eou(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PRINT_EDIT_DEPTH, _T("--print_edit_depth"), 0, SO_REQ_SEP, "\t--print_edit_depth=<val> Depth to truncate <edit> tag structure when converting a flame to xml. 0 prints all <edit> tags [default: 0].\n"));
INITUINTOPTION(Bits, Eou(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_BITS, _T("--bits"), 33, SO_REQ_SEP, "\t--bits=<val> Determines the types used for the calculations [default: 33].\n"
"\t\t\t\t\t32: float.\n"
"\t\t\t\t\t33: float.\n"//This differs from the original which used an int hist for bits 33.
"\t\t\t\t\t64: double.\n"));
INITUINTOPTION(PrintEditDepth, Eou(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PRINT_EDIT_DEPTH, _T("--print_edit_depth"), 0, SO_REQ_SEP, "\t--print_edit_depth=<val> Depth to truncate <edit> tag structure when converting a flame to Xml. 0 prints all <edit> tags [default: 0].\n"));
INITUINTOPTION(JpegQuality, Eou(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_JPEG, _T("--jpeg"), 95, SO_REQ_SEP, "\t--jpeg=<val> Jpeg quality 0-100 for compression [default: 95].\n"));
INITUINTOPTION(FirstFrame, Eou(eOptionUse::OPT_USE_ANIMATE, eOptionIDs::OPT_BEGIN, _T("--begin"), UINT_MAX, SO_REQ_SEP, "\t--begin=<val> Time of first frame to render [default: first time specified in file].\n"));
INITUINTOPTION(LastFrame, Eou(eOptionUse::OPT_USE_ANIMATE, eOptionIDs::OPT_END, _T("--end"), UINT_MAX, SO_REQ_SEP, "\t--end=<val> Time of last frame to render [default: last time specified in the input file].\n"));
@ -390,7 +389,6 @@ public:
INITSTRINGOPTION(Suffix, Eos(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_SUFFIX, _T("--suffix"), "", SO_REQ_SEP, "\t--suffix=<val> Suffix to append to all output files.\n"));
INITSTRINGOPTION(Format, Eos(eOptionUse::OPT_RENDER_ANIM, eOptionIDs::OPT_FORMAT, _T("--format"), "png", SO_REQ_SEP, "\t--format=<val> Format of the output file. Valid values are: bmp, jpg, png, ppm [default: png].\n"));
INITSTRINGOPTION(PalettePath, Eos(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PALETTE_FILE, _T("--flam3_palettes"), "flam3-palettes.xml", SO_REQ_SEP, "\t--flam3_palettes=<val> Path and name of the palette file [default: flam3-palettes.xml].\n"));
//INITSTRINGOPTION(PaletteImage, Eos(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_PALETTE_IMAGE, _T("--image"), "", SO_REQ_SEP, "\t--image=<val> Replace palette with png, jpg, or ppm image.\n"));
INITSTRINGOPTION(Id, Eos(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_ID, _T("--id"), "", SO_REQ_SEP, "\t--id=<val> ID to use in <edit> tags / image comments.\n"));
INITSTRINGOPTION(Url, Eos(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_URL, _T("--url"), "", SO_REQ_SEP, "\t--url=<val> URL to use in <edit> tags / image comments.\n"));
INITSTRINGOPTION(Nick, Eos(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_NICK, _T("--nick"), "", SO_REQ_SEP, "\t--nick=<val> Nickname to use in <edit> tags / image comments.\n"));
@ -465,7 +463,6 @@ public:
PARSEBOOLOPTION(eOptionIDs::OPT_POS_Y_UP, YAxisUp);
PARSEBOOLOPTION(eOptionIDs::OPT_TRANSPARENCY, Transparency);
PARSEBOOLOPTION(eOptionIDs::OPT_NAME_ENABLE, NameEnable);
PARSEBOOLOPTION(eOptionIDs::OPT_INT_PALETTE, IntPalette);
PARSEBOOLOPTION(eOptionIDs::OPT_HEX_PALETTE, HexPalette);
PARSEBOOLOPTION(eOptionIDs::OPT_INSERT_PALETTE, InsertPalette);
PARSEBOOLOPTION(eOptionIDs::OPT_JPEG_COMMENTS, JpegComments);
@ -667,17 +664,29 @@ public:
if (optUsage == eOptionUse::OPT_USE_RENDER)
{
cout << "Usage:\n"
"\tEmberRender.exe --in=test.flam3 [--out=outfile --format=png --verbose --progress --opencl]\n\n";
#ifdef _WIN32
"\tEmberRender.exe --in=test.flame [--out=outfile --format=png --verbose --progress --opencl]\n\n";
#else
"\temberrender --in=test.flame [--out=outfile --format=png --verbose --progress --opencl]\n\n";
#endif
}
else if (optUsage == eOptionUse::OPT_USE_ANIMATE)
{
cout << "Usage:\n"
"\tEmberAnimate.exe --in=sequence.flam3 [--format=png --verbose --progress --opencl]\n\n";
#ifdef _WIN32
"\tEmberAnimate.exe --in=sequence.flame [--format=png --verbose --progress --opencl]\n\n";
#else
"\temberanimate --in=sequence.flame [--format=png --verbose --progress --opencl]\n\n";
#endif
}
else if (optUsage == eOptionUse::OPT_USE_GENOME)
{
cout << "Usage:\n"
"\tEmberGenome.exe --sequence=test.flam3 > sequenceout.flam3\n\n";
#ifdef _WIN32
"\tEmberGenome.exe --sequence=test.flame > sequenceout.flame\n\n";
#else
"\tembergenome --sequence=test.flame > sequenceout.flame\n\n";
#endif
}
cout << GetUsage(optUsage) << "\n";
@ -730,7 +739,6 @@ public:
Eob YAxisUp;
Eob Transparency;
Eob NameEnable;
Eob IntPalette;
Eob HexPalette;
Eob InsertPalette;
Eob JpegComments;

View File

@ -118,7 +118,7 @@ bool EmberGenome(EmberOptions& opt)
EmberToXml<T> emberToXml;
EmberReport emberReport, emberReport2;
const vector<pair<size_t, size_t>> devices = Devices(opt.Devices());
unique_ptr<RenderProgress<T>> progress(new RenderProgress<T>());
auto progress = make_unique<RenderProgress<T>>();
unique_ptr<Renderer<T, float>> renderer(CreateRenderer<T>(opt.EmberCL() ? eRendererType::OPENCL_RENDERER : eRendererType::CPU_RENDERER, devices, false, 0, emberReport));
QTIsaac<ISAAC_SIZE, ISAAC_INT> rand(ISAAC_INT(t.Tic()), ISAAC_INT(t.Tic() * 2), ISAAC_INT(t.Tic() * 3));
vector<string> errorReport = emberReport.ErrorReport();
@ -337,7 +337,7 @@ bool EmberGenome(EmberOptions& opt)
tools.ApplyTemplate(embers[i], *pTemplate);
tools.Offset(embers[i], T(opt.OffsetX()), T(opt.OffsetY()));
cout << emberToXml.ToString(embers[i], opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(embers[i], opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
cout << "</clone_all>\n";
@ -399,7 +399,7 @@ bool EmberGenome(EmberOptions& opt)
if (pTemplate)
tools.ApplyTemplate(interpolated, *pTemplate);
cout << emberToXml.ToString(interpolated, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(interpolated, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
cout << "</animate>\n";
@ -434,7 +434,7 @@ bool EmberGenome(EmberOptions& opt)
blend = T(frame) / T(opt.Frames());
tools.Spin(embers[i], pTemplate, result, frameCount++, blend);//Result is cleared and reassigned each time inside of Spin().
FormatName(result, os, padding);
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
//The loop above will have rotated just shy of a complete rotation.
@ -458,7 +458,7 @@ bool EmberGenome(EmberOptions& opt)
result.Clear();
tools.SpinInter(&embers[i], pTemplate, result, frameCount++, seqFlag, blend);
FormatName(result, os, padding);
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
}
}
@ -466,7 +466,7 @@ bool EmberGenome(EmberOptions& opt)
result = embers.back();
tools.Spin(embers.back(), pTemplate, result, frameCount, 0);
FormatName(result, os, padding);
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
if (opt.Enclosed())
cout << "</sequence>\n";
@ -501,9 +501,9 @@ bool EmberGenome(EmberOptions& opt)
tools.Spin(embers[0], pTemplate, result1, frame - 1, blend - spread);
tools.Spin(embers[0], pTemplate, result2, frame , blend );
tools.Spin(embers[0], pTemplate, result3, frame + 1, blend + spread);
cout << emberToXml.ToString(result1, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result2, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result3, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result1, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
cout << emberToXml.ToString(result2, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
cout << emberToXml.ToString(result3, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
else
{
@ -516,9 +516,9 @@ bool EmberGenome(EmberOptions& opt)
tools.SpinInter(embers.data(), pTemplate, result1, frame - 1, 0, blend - spread);
tools.SpinInter(embers.data(), pTemplate, result2, frame , 0, blend );
tools.SpinInter(embers.data(), pTemplate, result3, frame + 1, 0, blend + spread);
cout << emberToXml.ToString(result1, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result2, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result3, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(result1, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
cout << emberToXml.ToString(result2, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
cout << emberToXml.ToString(result3, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
if (opt.Enclosed())
@ -548,7 +548,7 @@ bool EmberGenome(EmberOptions& opt)
tools.ApplyTemplate(embers[i], *pTemplate);
tools.Offset(embers[i], T(opt.OffsetX()), T(opt.OffsetY()));
cout << emberToXml.ToString(embers[i], opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(embers[i], opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
}
if (opt.Enclosed())
@ -792,7 +792,7 @@ bool EmberGenome(EmberOptions& opt)
save.DeleteTotalXform(save.TotalXformCount() - 1);
}
cout << emberToXml.ToString(save, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
cout << emberToXml.ToString(save, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), opt.HexPalette());
VerbosePrint("\nDone. Action = " << os.str() << "\n");
cout.flush();
save.Clear();

View File

@ -46,7 +46,7 @@ bool EmberRender(EmberOptions& opt)
EmberToXml<T> emberToXml;
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> randVec;
const vector<pair<size_t, size_t>> devices = Devices(opt.Devices());
unique_ptr<RenderProgress<T>> progress(new RenderProgress<T>());
auto progress = make_unique<RenderProgress<T>>();
unique_ptr<Renderer<T, float>> renderer(CreateRenderer<T>(opt.EmberCL() ? eRendererType::OPENCL_RENDERER : eRendererType::CPU_RENDERER, devices, false, 0, emberReport));
vector<string> errorReport = emberReport.ErrorReport();
@ -282,7 +282,7 @@ bool EmberRender(EmberOptions& opt)
//TotalIterCount() is actually using ScaledQuality() which does not get reset upon ember assignment,
//so it ends up using the correct value for quality * strips.
iterCount = renderer->TotalIterCount(1);
comments = renderer->ImageComments(stats, opt.PrintEditDepth(), opt.IntPalette(), opt.HexPalette());
comments = renderer->ImageComments(stats, opt.PrintEditDepth(), opt.HexPalette());
os.str("");
os << comments.m_NumIters << " / " << iterCount << " (" << std::fixed << std::setprecision(2) << ((double(stats.m_Iters) / double(iterCount)) * 100) << "%)";
VerbosePrint("\nIters ran/requested: " + os.str());

View File

@ -1984,6 +1984,18 @@ void TestRotate()
auto xrot = glm::rotate(xtrans, angle * DEG_2_RAD_T, v3T(0, 0, 1));
}
template<typename T>
class EmberContainerTester
{
public:
template <typename Alloc, template <typename, typename> class C>
static void TestEmberContainer(C<Ember<T>, Alloc>& cont)
{
Ember<T> e;
cont.push_back(e);
}
};
#define DO_NVIDIA 1
int _tmain(int argc, _TCHAR* argv[])
@ -1991,8 +2003,17 @@ int _tmain(int argc, _TCHAR* argv[])
//int i;
bool b = true;
Timing t(4);
QTIsaac<ISAAC_SIZE, ISAAC_INT> rand(1, 2, 3);
mt19937 meow(1729);
vector<Ember<float>> fv;
vector<Ember<double>> dv;
list<Ember<float>> fl;
list<Ember<double>> dl;
EmberContainerTester<float>::TestEmberContainer(fv);
EmberContainerTester<double>::TestEmberContainer(dv);
EmberContainerTester<float>::TestEmberContainer(fl);
EmberContainerTester<double>::TestEmberContainer(dl);
CopyCont(fv, fl);
//QTIsaac<ISAAC_SIZE, ISAAC_INT> rand(1, 2, 3);
//mt19937 meow(1729);
/* TestAffine<float>();
TestAffine<double>();*/
/* TestRotate<float>();

View File

@ -15,7 +15,7 @@ class FractoriumAboutDialog : public QDialog
{
Q_OBJECT
public:
FractoriumAboutDialog(QWidget* p = 0, Qt::WindowFlags f = 0);
FractoriumAboutDialog(QWidget* p = nullptr, Qt::WindowFlags f = 0);
private:
Ui::AboutDialog ui;

View File

@ -16,7 +16,7 @@ class DoubleSpinBox : public QDoubleSpinBox
Q_OBJECT
public:
explicit DoubleSpinBox(QWidget* parent = 0, int height = 16, double step = 0.05);
explicit DoubleSpinBox(QWidget* parent = nullptr, int height = 16, double step = 0.05);
virtual ~DoubleSpinBox() { }
void SetValueStealth(double d);
void DoubleClick(bool b);

View File

@ -17,11 +17,10 @@ class EmberFile
{
public:
/// <summary>
/// Empty constructor that does nothing.
/// Default constructor and destructor.
/// </summary>
EmberFile()
{
}
EmberFile() = default;
~EmberFile() = default;
/// <summary>
/// Default copy constructor.
@ -63,7 +62,31 @@ public:
EmberFile<T>& operator = (const EmberFile<U>& emberFile)
{
m_Filename = emberFile.m_Filename;
CopyVec(m_Embers, emberFile.m_Embers);
CopyCont(m_Embers, emberFile.m_Embers);
return *this;
}
/// <summary>
/// Move constructor.
/// </summary>
/// <param name="emberFile">The EmberFile object to move</param>
EmberFile(EmberFile<T>&& emberFile)
{
EmberFile<T>::operator=<T>(emberFile);
}
/// <summary>
/// Move assignment operator.
/// </summary>
/// <param name="emberFile">The EmberFile object to move</param>
EmberFile<T>& operator = (EmberFile<T>&& emberFile)
{
if (this != &emberFile)
{
m_Filename = emberFile.m_Filename;
m_Embers = std::move(emberFile.m_Embers);
}
return *this;
}
@ -84,6 +107,19 @@ public:
return m_Embers.size();
}
/// <summary>
/// Get a pointer to the ember at the specified index.
/// </summary>
/// <param name="i">The index of the ember to retrieve</param>
/// <returns>A pointer to the ember if it was within bounds, else nullptr.</returns>
Ember<T>* Get(size_t i)
{
if (i < m_Embers.size())
return &(*Advance(m_Embers.begin(), i));
return nullptr;
}
/// <summary>
/// Delete the ember at the given index.
/// Will not delete anything if the size is already 1.
@ -94,7 +130,7 @@ public:
{
if (Size() > 1 && index < Size())
{
m_Embers.erase(m_Embers.begin() + index);
m_Embers.erase(Advance(m_Embers.begin(), index));
return true;
}
else
@ -106,14 +142,14 @@ public:
/// </summary>
void MakeNamesUnique()
{
for (size_t i = 0; i < m_Embers.size(); i++)
for (auto it1 = m_Embers.begin(); it1 != m_Embers.end(); ++it1)
{
for (size_t j = 0; j < m_Embers.size(); j++)
for (auto it2 = m_Embers.begin(); it2 != m_Embers.end(); ++it2)
{
if (i != j && m_Embers[i].m_Name == m_Embers[j].m_Name)
if (it1 != it2 && it1->m_Name == it2->m_Name)
{
m_Embers[j].m_Name = IncrementTrailingUnderscoreInt(QString::fromStdString(m_Embers[j].m_Name)).toStdString();
j = 0;
it2->m_Name = IncrementTrailingUnderscoreInt(QString::fromStdString(it2->m_Name)).toStdString();
it2 = m_Embers.begin();
}
}
}
@ -195,5 +231,5 @@ public:
}
QString m_Filename;
vector<Ember<T>> m_Embers;
list<Ember<T>> m_Embers;
};

View File

@ -44,7 +44,7 @@ public:
{
int size = 64;
m_Image = QImage(width, height, QImage::Format_RGBA8888);
memcpy(m_Image.scanLine(0), v.data(), v.size() * sizeof(v[0]));//Memcpy the data in.
memcpy(m_Image.scanLine(0), v.data(), SizeOf(v));//Memcpy the data in.
m_Pixmap = QPixmap::fromImage(m_Image).scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//Create a QPixmap out of the QImage, scaled to size.
setData(0, Qt::DecorationRole, m_Pixmap);
}
@ -68,10 +68,11 @@ public:
/// </summary>
/// <param name="ember">A pointer to the ember this item will represent</param>
/// <param name="p">The parent widget of this item</param>
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidget* p = 0)
: EmberTreeWidgetItemBase(p)
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidget* p = nullptr)
: EmberTreeWidgetItemBase(p),
m_Ember(ember)
{
m_Ember = ember;
setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
}
/// <summary>
@ -80,10 +81,11 @@ public:
/// </summary>
/// <param name="ember">A pointer to the ember this item will represent</param>
/// <param name="p">The parent widget of this item</param>
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidgetItem* p = 0)
: EmberTreeWidgetItemBase(p)
explicit EmberTreeWidgetItem(Ember<T>* ember, QTreeWidgetItem* p = nullptr)
: EmberTreeWidgetItemBase(p),
m_Ember(ember)
{
m_Ember = ember;
setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
}
/// <summary>

View File

@ -10,13 +10,10 @@
/// </summary>
/// <param name="finalRender">Pointer to the final render dialog</param>
FinalRenderEmberControllerBase::FinalRenderEmberControllerBase(FractoriumFinalRenderDialog* finalRenderDialog)
: FractoriumEmberControllerBase(finalRenderDialog->m_Fractorium)
: FractoriumEmberControllerBase(finalRenderDialog->m_Fractorium),
m_FinalRenderDialog(finalRenderDialog)
{
m_Run = false;
m_PreviewRun = false;
m_ImageCount = 0;
m_FinishedImageCount.store(0);
m_FinalRenderDialog = finalRenderDialog;
m_Settings = m_Fractorium->m_Settings;
}
@ -105,7 +102,7 @@ template<typename T>
FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderDialog* finalRender)
: FinalRenderEmberControllerBase(finalRender)
{
m_FinalPreviewRenderer = unique_ptr<EmberNs::Renderer<T, float>>(new EmberNs::Renderer<T, float>());
m_FinalPreviewRenderer = make_unique<EmberNs::Renderer<T, float>>();
m_FinalPreviewRenderer->Callback(nullptr);
m_FinalPreviewRenderer->NumChannels(4);
m_FinalPreviewRenderFunc = [&]()
@ -157,10 +154,10 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
m_Run = true;
m_TotalTimer.Tic();//Begin timing for progress of all operations.
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
size_t i;
size_t i = 0;
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
size_t currentStripForProgress = 0;//Sort of a hack to get the strip value to the progress function.
QString path = doAll ? ComposePath(QString::fromStdString(m_EmberFile.m_Embers[0].m_Name)) : ComposePath(Name());
QString path = doAll ? ComposePath(QString::fromStdString(m_EmberFile.m_Embers.begin()->m_Name)) : ComposePath(Name());
QString backup = path + "_backup.flame";
//Save backup Xml.
@ -186,33 +183,40 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
//Different action required for rendering as animation or not.
if (m_GuiState.m_DoSequence && !m_Renderers.empty())
{
Ember<T>* firstEmber = &m_EmberFile.m_Embers[0];
Ember<T>* prev = nullptr;
vector<Ember<T>> embers;
vector<std::thread> threadVec;
std::atomic<size_t> atomfTime;
auto firstEmber = m_EmberFile.m_Embers.begin();
//Need to loop through and set all w, h, q, ts, ss and t vals.
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
for (auto& it : m_EmberFile.m_Embers)
{
SyncGuiToEmber(m_EmberFile.m_Embers[i], firstEmber->m_FinalRasW, firstEmber->m_FinalRasH);
if (!m_Run)
break;
if (i > 0)
SyncGuiToEmber(it, firstEmber->m_FinalRasW, firstEmber->m_FinalRasH);
if (&it == &(*firstEmber))//First.
{
if (m_EmberFile.m_Embers[i].m_Time <= m_EmberFile.m_Embers[i - 1].m_Time)
m_EmberFile.m_Embers[i].m_Time = m_EmberFile.m_Embers[i - 1].m_Time + 1;
it.m_Time = 0;
}
else if (i == 0)
else//All others
{
m_EmberFile.m_Embers[i].m_Time = 0;
if (it.m_Time <= prev->m_Time)
it.m_Time = prev->m_Time + 1;
}
m_EmberFile.m_Embers[i].m_TemporalSamples = m_GuiState.m_TemporalSamples;
it.m_TemporalSamples = m_GuiState.m_TemporalSamples;
prev = &it;
}
std::atomic<size_t> atomfTime;
vector<std::thread> threadVec;
//Not supporting strips with animation.
//Shouldn't be a problem because animations will be at max 4k x 2k which will take about 1GB
//even when using double precision, which most cards at the time of this writing already exceed.
m_GuiState.m_Strips = 1;
atomfTime.store(0);
CopyCont(embers, m_EmberFile.m_Embers);
std::function<void(size_t)> iterFunc = [&](size_t index)
{
size_t ftime;
@ -223,13 +227,13 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
EmberImageComments comments;
Timing renderTimer;
auto renderer = m_Renderers[index].get();
renderer->SetEmber(m_EmberFile.m_Embers);//Copy all embers to the local storage inside the renderer.
renderer->SetExternalEmbersPointer(&embers);//All will share a pointer to the original vector to conserve memory with large files. Ok because the vec doesn't get modified.
//Render each image, cancelling if m_Run ever gets set to false.
while (atomfTime.fetch_add(1), ((ftime = atomfTime.load() - 1) < m_EmberFile.Size()) && m_Run)//Needed to set 1 to claim this iter from other threads, so decrement it to be zero-indexed here.
{
T localTime = T(ftime);
Output("Image " + ToString(ftime + 1ULL) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[ftime].m_Name)));
Output("Image " + ToString(ftime + 1ULL) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.Get(ftime)->m_Name)));
renderer->Reset();//Have to manually set this since the ember is not set each time through.
renderTimer.Tic();//Toc() is called in RenderComplete().
@ -247,10 +251,10 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
writeThread.join();
stats = renderer->Stats();
comments = renderer->ImageComments(stats, 0, false, true);
comments = renderer->ImageComments(stats, 0, true);
writeThread = std::thread([&](size_t tempTime, size_t threadFinalImageIndex)
{
SaveCurrentRender(m_EmberFile.m_Embers[tempTime],
SaveCurrentRender(*m_EmberFile.Get(tempTime),
comments,//These all don't change during the renders, so it's ok to access them in the thread.
finalImages[threadFinalImageIndex],
renderer->FinalRasW(),
@ -259,7 +263,7 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
renderer->BytesPerChannel());
}, ftime, finalImageIndex);
m_FinishedImageCount.fetch_add(1);
RenderComplete(m_EmberFile.m_Embers[ftime], stats, renderTimer);
RenderComplete(*m_EmberFile.Get(ftime), stats, renderTimer);
if (!index)//Only first device has a progress callback, so it also makes sense to only manually set the progress on the first device as well.
HandleFinishedProgress();
@ -290,16 +294,19 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
else if (m_Renderer.get())//Make sure a renderer was created and render all images, but not as an animation sequence (without temporal samples motion blur).
{
//Render each image, cancelling if m_Run ever gets set to false.
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
for (auto& it : m_EmberFile.m_Embers)
{
Output("Image " + ToString<qulonglong>(m_FinishedImageCount.load() + 1) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[i].m_Name)));
m_EmberFile.m_Embers[i].m_TemporalSamples = 1;//No temporal sampling.
m_Renderer->SetEmber(m_EmberFile.m_Embers[i]);
if (!m_Run)
break;
Output("Image " + ToString<qulonglong>(m_FinishedImageCount.load() + 1) + ":\n" + ComposePath(QString::fromStdString(it.m_Name)));
it.m_TemporalSamples = 1;//No temporal sampling.
m_Renderer->SetEmber(it);
m_Renderer->PrepFinalAccumVector(m_FinalImage);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run().
m_Stats.Clear();
Memset(m_FinalImage);
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
StripsRender<T>(m_Renderer.get(), m_EmberFile.m_Embers[i], m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
StripsRender<T>(m_Renderer.get(), it, m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
[&](size_t strip) { m_Stats += m_Renderer->Stats(); },//Post strip.
[&](size_t strip)//Error.
@ -371,28 +378,24 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<float>& emberFile)
{
m_EmberFile = emberFile;
if (m_EmberFile.Size())
m_Ember = &(m_EmberFile.m_Embers[0]);
m_Ember = m_EmberFile.Get(0);
}
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
#ifdef DO_DOUBLE
template <typename T> void FinalRenderEmberController<T>::SetEmberFile(const EmberFile<double>& emberFile)
{
m_EmberFile = emberFile;
if (m_EmberFile.Size())
m_Ember = &(m_EmberFile.m_Embers[0]);
m_Ember = m_EmberFile.Get(0);
}
template <typename T> void FinalRenderEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
#endif
@ -407,12 +410,12 @@ void FinalRenderEmberController<T>::SetEmber(size_t index)
{
if (index < m_EmberFile.Size())
{
m_Ember = &(m_EmberFile.m_Embers[index]);
m_Ember = m_EmberFile.Get(index);
SyncCurrentToGui();
}
else if (m_EmberFile.Size() > 1)
{
m_Ember = &(m_EmberFile.m_Embers[0]);//Should never happen.
m_Ember = m_EmberFile.Get(0);//Should never happen.
}
}
@ -774,7 +777,7 @@ void FinalRenderEmberController<T>::CancelPreviewRender()
template<typename T>
void FinalRenderEmberController<T>::SaveCurrentRender(Ember<T>& ember)
{
auto comments = m_Renderer->ImageComments(m_Stats, 0, false, true);
auto comments = m_Renderer->ImageComments(m_Stats, 0, true);
SaveCurrentRender(ember, comments, m_FinalImage, m_Renderer->FinalRasW(), m_Renderer->FinalRasH(), m_Renderer->NumChannels(), m_Renderer->BytesPerChannel());
}

View File

@ -73,9 +73,9 @@ public:
void Output(const QString& s);
protected:
bool m_Run;
bool m_PreviewRun;
size_t m_ImageCount;
bool m_Run = false;
bool m_PreviewRun = false;
size_t m_ImageCount = 0;
std::atomic<size_t> m_FinishedImageCount;
QFuture<void> m_Result;

View File

@ -140,7 +140,7 @@ Fractorium::Fractorium(QWidget* p)
connect(ui.LibraryDockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(dockLocationChanged(Qt::DockWidgetArea)));
connect(ui.LibraryDockWidget, SIGNAL(topLevelChanged(bool)), this, SLOT(OnDockTopLevelChanged(bool)));
//Always ensure the library tab is selected, which will show preview renders.
//Always ensure the library tab is selected if not restoring, which will show preview renders.
if (!restored)
{
ui.LibraryDockWidget->raise();
@ -298,6 +298,7 @@ void Fractorium::dockLocationChanged(Qt::DockWidgetArea area)
/// Event filter for taking special action on:
/// Dock widget resize events, which in turn trigger GLParentScrollArea events.
/// Library tree key events, specifically delete.
/// Library tree drag n drop events.
/// </summary>
/// <param name="o">The object</param>
/// <param name="e">The eevent</param>
@ -309,7 +310,7 @@ bool Fractorium::eventFilter(QObject* o, QEvent* e)
m_WidthSpin->DoubleClickNonZero(ui.GLParentScrollArea->width());
m_HeightSpin->DoubleClickNonZero(ui.GLParentScrollArea->height());
}
else if (QKeyEvent* ke = dynamic_cast<QKeyEvent*>(e))
else if (auto ke = dynamic_cast<QKeyEvent*>(e))
{
bool shift = QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
@ -499,7 +500,7 @@ QStringList Fractorium::SetupOpenXmlDialog()
QStringList filenames;
m_FileDialog->disconnect(SIGNAL(filterSelected(const QString&)));
connect(m_FileDialog, &QFileDialog::filterSelected, [ = ](const QString & filter) { m_Settings->OpenXmlExt(filter); });
connect(m_FileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->OpenXmlExt(filter); });
m_FileDialog->setFileMode(QFileDialog::ExistingFiles);
m_FileDialog->setAcceptMode(QFileDialog::AcceptOpen);
m_FileDialog->setNameFilter("Flam3 (*.flam3);;Flame (*.flame);;Xml (*.xml)");
@ -527,6 +528,7 @@ QStringList Fractorium::SetupOpenXmlDialog()
QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
{
//Lazy instantiate since it takes a long time.
//QS
if (!m_FileDialog)
{
m_FileDialog = new QFileDialog(this);
@ -538,7 +540,7 @@ QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
QString filename;
m_FileDialog->disconnect(SIGNAL(filterSelected(const QString&)));
connect(m_FileDialog, &QFileDialog::filterSelected, [ = ](const QString & filter) { m_Settings->SaveXmlExt(filter); });
connect(m_FileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->SaveXmlExt(filter); });
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FileDialog->setAcceptMode(QFileDialog::AcceptSave);
@ -549,7 +551,19 @@ QString Fractorium::SetupSaveXmlDialog(const QString& defaultFilename)
m_FileDialog->selectNameFilter(m_Settings->SaveXmlExt());
if (m_FileDialog->exec() == QDialog::Accepted)
{
filename = m_FileDialog->selectedFiles().value(0);
//For some reason, linux doesn't automatically append this, but Windows does. Force it to be safe.
auto filt = m_FileDialog->selectedNameFilter().split('*');//Qt makes it very hard to get the actual extension used.
if (filt.size() > 1)//Should always be true.
{
auto s = filt[1].replace(")", "");
if (!filename.endsWith(s))
filename.append(s);
}
}
return filename;
}
@ -574,7 +588,7 @@ QString Fractorium::SetupSaveImageDialog(const QString& defaultFilename)
QString filename;
m_FileDialog->disconnect(SIGNAL(filterSelected(const QString&)));
connect(m_FileDialog, &QFileDialog::filterSelected, [ = ](const QString & filter) { m_Settings->SaveImageExt(filter); });
connect(m_FileDialog, &QFileDialog::filterSelected, [&](const QString & filter) { m_Settings->SaveImageExt(filter); });
//This must come first because it clears various internal states which allow the file text to be properly set.
//This is most likely a bug in QFileDialog.
m_FileDialog->setAcceptMode(QFileDialog::AcceptSave);

View File

@ -65,6 +65,7 @@ class Fractorium : public QMainWindow
friend GLWidget;
friend QssDialog;
friend LibraryTreeWidget;
friend FractoriumOptionsDialog;
friend FractoriumFinalRenderDialog;
friend FractoriumAboutDialog;
@ -82,7 +83,7 @@ class Fractorium : public QMainWindow
#endif
public:
Fractorium(QWidget* p = 0);
Fractorium(QWidget* p = nullptr);
~Fractorium();
//Geometry.

View File

@ -6681,12 +6681,15 @@
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTreeWidget" name="LibraryTree">
<widget class="LibraryTreeWidget" name="LibraryTree">
<property name="focusPolicy">
<enum>Qt::WheelFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
<enum>Qt::DefaultContextMenu</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
@ -6697,6 +6700,21 @@
<property name="editTriggers">
<set>QAbstractItemView::SelectedClicked</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>true</bool>
</property>
<property name="dragEnabled">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="indentation">
<number>10</number>
</property>
@ -7239,6 +7257,11 @@
<extends>QGraphicsView</extends>
<header>CurvesGraphicsView.h</header>
</customwidget>
<customwidget>
<class>LibraryTreeWidget</class>
<extends>QTreeWidget</extends>
<header>LibraryTreeWidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>LibraryDockWidget</tabstop>

View File

@ -11,21 +11,12 @@
FractoriumEmberControllerBase::FractoriumEmberControllerBase(Fractorium* fractorium)
{
Timing t;
m_Rendering = false;
m_Shared = true;
m_FailedRenders = 0;
m_UndoIndex = 0;
m_LockedScale = 1;
m_RenderType = eRendererType::CPU_RENDERER;
m_OutputTexID = 0;
m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
m_Fractorium = fractorium;
m_Info = OpenCLInfo::Instance();
m_Rand = QTIsaac<ISAAC_SIZE, ISAAC_INT>(ISAAC_INT(t.Tic()), ISAAC_INT(t.Tic() * 2), ISAAC_INT(t.Tic() * 3));//Ensure a different rand seed on each instance.
m_RenderTimer = std::unique_ptr<QTimer>(new QTimer(m_Fractorium));
m_RenderTimer = make_unique<QTimer>(m_Fractorium);
m_RenderTimer->setInterval(0);
m_Fractorium->connect(m_RenderTimer.get(), SIGNAL(timeout()), SLOT(IdleTimer()));
m_RenderRestartTimer = std::unique_ptr<QTimer>(new QTimer(m_Fractorium));
m_RenderRestartTimer = make_unique<QTimer>(m_Fractorium);
m_Fractorium->connect(m_RenderRestartTimer.get(), SIGNAL(timeout()), SLOT(StartRenderTimer()));
}
@ -52,10 +43,7 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
m_VariationList(VariationList<T>::Instance())
{
bool b = false;
m_PreviewRun = false;
m_PreviewRunning = false;
m_GLController = unique_ptr<GLEmberController<T>>(new GLEmberController<T>(fractorium, fractorium->ui.GLDisplay, this));
m_PreviewRenderer = unique_ptr<EmberNs::Renderer<T, float>>(new EmberNs::Renderer<T, float>());
m_GLController = make_unique<GLEmberController<T>>(fractorium, fractorium->ui.GLDisplay, this);
//Initial combo change event to fill the palette table will be called automatically later.
//Look hard for a palette.
static vector<string> paths =
@ -72,8 +60,7 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
{
if (b = InitPaletteList(path))
{
m_SheepTools = unique_ptr<SheepTools<T, float>>(new SheepTools<T, float>(
m_PaletteList.Name(0), new EmberNs::Renderer<T, float>()));
m_SheepTools = make_unique<SheepTools<T, float>>(m_PaletteList.Name(0), new EmberNs::Renderer<T, float>());
break;
}
}
@ -102,9 +89,11 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
if (auto top = tree->topLevelItem(0))
{
for (auto i = start; m_PreviewRun && i < end && i < m_EmberFile.Size(); i++)
size_t i = start;
for (auto b = Advance(m_EmberFile.m_Embers.begin(), start); m_PreviewRun && i < end && b != m_EmberFile.m_Embers.end(); ++b, ++i)
{
Ember<T> ember = m_EmberFile.m_Embers[i];
Ember<T> ember = *b;
ember.SyncSize();
ember.SetSizeAndAdjustScale(PREVIEW_SIZE, PREVIEW_SIZE, false, eScaleType::SCALE_WIDTH);
ember.m_TemporalSamples = 1;
@ -124,7 +113,6 @@ FractoriumEmberController<T>::FractoriumEmberController(Fractorium* fractorium)
Q_ARG(vector<byte>&, m_PreviewFinalImage),
Q_ARG(uint, PREVIEW_SIZE),
Q_ARG(uint, PREVIEW_SIZE));
//treeItem->SetImage(m_PreviewFinalImage, PREVIEW_SIZE, PREVIEW_SIZE);
}
}
}
@ -152,7 +140,7 @@ template <typename T> void FractoriumEmberController<T>::SetEmberFile(const Embe
template <typename T> void FractoriumEmberController<T>::CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
template <typename T> void FractoriumEmberController<T>::SetTempPalette(const Palette<float>& palette) { m_TempPalette = palette; }
@ -164,7 +152,7 @@ template <typename T> void FractoriumEmberController<T>::SetEmberFile(const Embe
template <typename T> void FractoriumEmberController<T>::CopyEmberFile(EmberFile<double>& emberFile, std::function<void(Ember<double>& ember)> perEmberOperation)
{
emberFile.m_Filename = m_EmberFile.m_Filename;
CopyVec(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
CopyCont(emberFile.m_Embers, m_EmberFile.m_Embers, perEmberOperation);
}
template <typename T> void FractoriumEmberController<T>::SetTempPalette(const Palette<double>& palette) { m_TempPalette = palette; }
@ -200,7 +188,7 @@ void FractoriumEmberController<T>::SetEmber(size_t index)
}
ClearUndo();
SetEmber(m_EmberFile.m_Embers[index]);
SetEmber(*m_EmberFile.Get(index));
}
}
@ -340,10 +328,10 @@ void FractoriumEmberController<T>::SetEmberPrivate(const Ember<U>& ember, bool v
size_t w = m_Ember.m_FinalRasW;//Cache values for use below.
size_t h = m_Ember.m_FinalRasH;
m_Ember = ember;
m_EmberFilePointer = &ember;
if (!verbatim)
{
//m_Ember.SetSizeAndAdjustScale(m_Fractorium->ui.GLDisplay->width(), m_Fractorium->ui.GLDisplay->height(), true, SCALE_WIDTH);
m_Ember.m_TemporalSamples = 1;//Change once animation is supported.
m_Ember.m_Quality = m_Fractorium->m_QualitySpin->value();
m_Ember.m_Supersample = m_Fractorium->m_SupersampleSpin->value();

View File

@ -18,6 +18,12 @@ enum class eEditUndoState : et { REGULAR_EDIT, UNDO_REDO, EDIT_UNDO };
/// </summary>
enum class eXformUpdate : et { UPDATE_CURRENT, UPDATE_SELECTED, UPDATE_CURRENT_AND_SELECTED, UPDATE_SELECTED_EXCEPT_FINAL, UPDATE_ALL, UPDATE_ALL_EXCEPT_FINAL };
/// <summary>
/// An enum representing the type of synchronizing to do between the list of Embers kept in memory
/// and the widgets in the library tree.
/// </summary>
enum eLibraryUpdate { INDEX = 1, NAME = 2, POINTER = 4 };
/// <summary>
/// FractoriumEmberController and Fractorium need each other, but each can't include the other.
/// So Fractorium includes this file, and Fractorium is declared as a forward declaration here.
@ -42,6 +48,7 @@ class FractoriumEmberControllerBase : public RenderCallback
{
public:
FractoriumEmberControllerBase(Fractorium* fractorium);
FractoriumEmberControllerBase(const FractoriumEmberControllerBase& controller) = delete;
virtual ~FractoriumEmberControllerBase();
//Embers.
@ -107,14 +114,14 @@ public:
//Toolbar.
//Library.
virtual void SyncNames() { }
virtual void SyncPointers() { }
virtual void SyncLibrary(eLibraryUpdate update) { }
virtual void FillLibraryTree(int selectIndex = -1) { }
virtual void UpdateLibraryTree() { }
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) { }
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { }
virtual void RenderPreviews(uint start = UINT_MAX, uint end = UINT_MAX) { }
virtual void StopPreviewRender() { }
virtual void MoveLibraryItems(int startRow, int destRow) { }
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) { }
//Params.
@ -237,17 +244,17 @@ protected:
eProcessState ProcessState() { return m_Renderer.get() ? m_Renderer->ProcessState() : eProcessState::NONE; }
//Non-templated members.
bool m_Rendering;
bool m_Shared;
bool m_Rendering = false;
bool m_Shared = true;
bool m_LastEditWasUndoRedo;
vector<pair<size_t, size_t>> m_Devices;
size_t m_SubBatchCount;
uint m_FailedRenders;
size_t m_UndoIndex;
double m_LockedScale;
eRendererType m_RenderType;
size_t m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
uint m_FailedRenders = 0;
size_t m_UndoIndex = 0;
double m_LockedScale = 1;
eRendererType m_RenderType = eRendererType::CPU_RENDERER;
eEditUndoState m_EditState;
GLuint m_OutputTexID;
GLuint m_OutputTexID = 0;
Timing m_RenderElapsedTimer;
EmberStats m_Stats;
QImage m_FinalPaletteImage;
@ -265,7 +272,7 @@ protected:
Fractorium* m_Fractorium;
std::unique_ptr<QTimer> m_RenderTimer;
std::unique_ptr<QTimer> m_RenderRestartTimer;
shared_ptr<OpenCLInfo> m_Info;
shared_ptr<OpenCLInfo> m_Info = OpenCLInfo::Instance();
};
/// <summary>
@ -279,6 +286,7 @@ class FractoriumEmberController : public FractoriumEmberControllerBase
{
public:
FractoriumEmberController(Fractorium* fractorium);
FractoriumEmberController(const FractoriumEmberController<T>& controller) = delete;
virtual ~FractoriumEmberController();
//Embers.
@ -347,10 +355,10 @@ public:
//Toolbar.
//Library.
virtual void SyncNames() override;
virtual void SyncPointers() override;
virtual void SyncLibrary(eLibraryUpdate update) override;
virtual void FillLibraryTree(int selectIndex = -1) override;
virtual void UpdateLibraryTree() override;
virtual void MoveLibraryItems(int startRow, int destRow) override;
virtual void Delete(const pair<size_t, QTreeWidgetItem*>& p) override;
virtual void EmberTreeItemChanged(QTreeWidgetItem* item, int col) override;
virtual void EmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) override;
@ -489,11 +497,12 @@ private:
bool SyncSizes();
//Templated members.
bool m_PreviewRun;
bool m_PreviewRunning;
bool m_PreviewRun = false;
bool m_PreviewRunning = false;
vector<T> m_TempOpacities;
vector<T> m_NormalizedWeights;
Ember<T> m_Ember;
const void* m_EmberFilePointer = nullptr;
EmberFile<T> m_EmberFile;
deque<Ember<T>> m_UndoList;
vector<Xform<T>> m_CopiedXforms;
@ -503,7 +512,7 @@ private:
VariationList<T>& m_VariationList;
unique_ptr<SheepTools<T, float>> m_SheepTools;
unique_ptr<GLEmberController<T>> m_GLController;
unique_ptr<EmberNs::Renderer<T, float>> m_PreviewRenderer;
unique_ptr<EmberNs::Renderer<T, float>> m_PreviewRenderer = make_unique<EmberNs::Renderer<T, float>>();
QFuture<void> m_PreviewResult;
std::function<void (uint, uint)> m_PreviewRenderFunc;
};

View File

@ -6,12 +6,12 @@
/// </summary>
void Fractorium::InitLibraryUI()
{
ui.LibraryTree->SetMainWindow(this);
connect(ui.LibraryTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemChanged(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
connect(ui.LibraryTree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(OnEmberTreeItemDoubleClicked(QTreeWidgetItem*, int)), Qt::QueuedConnection);
}
/// <summary>
/// Get the index of the currently selected ember in the library tree.
/// </summary>
@ -52,44 +52,30 @@ void Fractorium::SetLibraryTreeItemData(EmberTreeWidgetItemBase* item, vector<by
/// <summary>
/// Set all libary tree entries to the name of the corresponding ember they represent.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::SyncNames()
{
EmberTreeWidgetItem<T>* item;
auto tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (auto top = tree->topLevelItem(0))
{
for (int i = 0; i < top->childCount(); i++)//Iterate through all of the children, which will represent the open embers.
{
if ((item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i))) && i < m_EmberFile.Size())//Cast the child widget to the EmberTreeWidgetItem type.
item->setText(0, QString::fromStdString(m_EmberFile.m_Embers[i].m_Name));
}
}
tree->blockSignals(false);
}
/// <summary>
/// Set all libary tree entries to point to the underlying ember they represent.
/// </summary>
template <typename T>
void FractoriumEmberController<T>::SyncPointers()
void FractoriumEmberController<T>::SyncLibrary(eLibraryUpdate update)
{
EmberTreeWidgetItem<T>* item;
auto it = m_EmberFile.m_Embers.begin();
auto tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (auto top = tree->topLevelItem(0))
{
size_t childCount = top->childCount();
for (int i = 0; i < childCount; i++)//Iterate through all of the children, which will represent the open embers.
for (int i = 0; i < top->childCount() && it != m_EmberFile.m_Embers.end(); ++i, ++it)//Iterate through all of the children, which will represent the open embers.
{
if ((item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i))) && i < m_EmberFile.Size())//Cast the child widget to the EmberTreeWidgetItem type.
item->SetEmberPointer(&m_EmberFile.m_Embers[i]);
if (auto item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))//Cast the child widget to the EmberTreeWidgetItem type.
{
if (update & eLibraryUpdate::INDEX)
it->m_Index = i;
if (update & eLibraryUpdate::NAME)
item->setText(0, QString::fromStdString(it->m_Name));
if (update & eLibraryUpdate::POINTER)
item->SetEmberPointer(&(*it));
}
}
}
@ -105,7 +91,8 @@ void FractoriumEmberController<T>::SyncPointers()
template <typename T>
void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
{
uint j, size = 64;
uint size = 64;
uint i = 0;
auto tree = m_Fractorium->ui.LibraryTree;
vector<byte> v(size * size * 4);
StopPreviewRender();
@ -116,18 +103,16 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
QFileInfo info(m_EmberFile.m_Filename);
fileItem->setText(0, info.fileName());
fileItem->setToolTip(0, m_EmberFile.m_Filename);
fileItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
fileItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled);
for (j = 0; j < m_EmberFile.Size(); j++)
for (auto& it : m_EmberFile.m_Embers)
{
auto ember = &m_EmberFile.m_Embers[j];
auto emberItem = new EmberTreeWidgetItem<T>(ember, fileItem);
emberItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
auto emberItem = new EmberTreeWidgetItem<T>(&it, fileItem);
if (ember->m_Name.empty())
emberItem->setText(0, ToString(j));
if (it.m_Name.empty())
emberItem->setText(0, ToString(i++));
else
emberItem->setText(0, ember->m_Name.c_str());
emberItem->setText(0, it.m_Name.c_str());
emberItem->setToolTip(0, emberItem->text(0));
emberItem->SetImage(v, size, size);
@ -152,35 +137,33 @@ void FractoriumEmberController<T>::FillLibraryTree(int selectIndex)
template <typename T>
void FractoriumEmberController<T>::UpdateLibraryTree()
{
uint i, size = 64;
auto tree = m_Fractorium->ui.LibraryTree;
uint size = 64;
vector<byte> v(size * size * 4);
auto tree = m_Fractorium->ui.LibraryTree;
if (auto top = tree->topLevelItem(0))
{
int childCount = top->childCount();
int origChildCount = top->childCount();
int i = origChildCount;
tree->blockSignals(true);
for (i = childCount; i < m_EmberFile.Size(); i++)
for (auto it = Advance(m_EmberFile.m_Embers.begin(), i); it != m_EmberFile.m_Embers.end(); ++it)
{
Ember<T>* ember = &m_EmberFile.m_Embers[i];
auto emberItem = new EmberTreeWidgetItem<T>(ember, top);
emberItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
auto emberItem = new EmberTreeWidgetItem<T>(&(*it), top);
if (ember->m_Name.empty())
emberItem->setText(0, ToString(i));
if (it->m_Name.empty())
emberItem->setText(0, ToString(i++));
else
emberItem->setText(0, ember->m_Name.c_str());
emberItem->setText(0, it->m_Name.c_str());
emberItem->setToolTip(0, emberItem->text(0));
emberItem->SetImage(v, size, size);
}
//When adding elements to the vector, they may have been reshuffled which will have invalidated
//the pointers contained in the EmberTreeWidgetItems. So reassign all pointers here.
SyncPointers();
//When adding elements, ensure all indices are sequential.
SyncLibrary(eLibraryUpdate::INDEX);
tree->blockSignals(false);
RenderPreviews(childCount, uint(m_EmberFile.Size()));
RenderPreviews(origChildCount, uint(m_EmberFile.Size()));
}
}
@ -200,9 +183,8 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
try
{
auto tree = m_Fractorium->ui.LibraryTree;
auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item);
if (emberItem)
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item))
{
if (emberItem->text(0).isEmpty())//Prevent empty string.
{
@ -214,10 +196,10 @@ void FractoriumEmberController<T>::EmberTreeItemChanged(QTreeWidgetItem* item, i
tree->blockSignals(true);
emberItem->UpdateEmberName();//Copy edit text to the ember's name variable.
m_EmberFile.MakeNamesUnique();//Ensure all names remain unique.
SyncNames();//Copy all ember names to the tree items since some might have changed to be made unique.
SyncLibrary(eLibraryUpdate::NAME);//Copy all ember names to the tree items since some might have changed to be made unique.
string newName = emberItem->GetEmber()->m_Name;//Get the new, final, unique name.
if (m_Ember.m_Name == oldName && oldName != newName)//If the ember edited was the current one, and the name was indeed changed, update the name of the current one.
if (m_EmberFilePointer == emberItem->GetEmber() && oldName != newName)//If the ember edited was the current one, and the name was indeed changed, update the name of the current one.
{
m_Ember.m_Name = newName;
m_LastSaveCurrent = "";//Reset will force the dialog to show on the next save current since the user probably wants a different name.
@ -259,6 +241,7 @@ void FractoriumEmberController<T>::EmberTreeItemDoubleClicked(QTreeWidgetItem* i
{
if (auto emberItem = dynamic_cast<EmberTreeWidgetItem<T>*>(item))
{
//qDebug() << "Setting current ember to: " << QString::fromStdString(emberItem->GetEmber()->m_Name);
ClearUndo();
SetEmber(*emberItem->GetEmber());
}
@ -266,6 +249,24 @@ void FractoriumEmberController<T>::EmberTreeItemDoubleClicked(QTreeWidgetItem* i
void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) { m_Controller->EmberTreeItemDoubleClicked(item, col); }
/// <summary>
/// Move a library item at one index to the next index.
/// </summary>
/// <param name="startRow">The index of the source item to move</param>
/// <param name="destRow">The destination index to move the item to</param>
template <typename T>
void FractoriumEmberController<T>::MoveLibraryItems(int startRow, int destRow)
{
int i = 0;
auto tree = m_Fractorium->ui.LibraryTree;
auto top = tree->topLevelItem(0);
auto b = m_EmberFile.m_Embers.begin();
auto s = Advance(b, startRow);
auto d = Advance(b, destRow);
m_EmberFile.m_Embers.splice(d, m_EmberFile.m_Embers, s);
SyncLibrary(eLibraryUpdate::INDEX);//Only indices need syncing.
}
/// <summary>
/// Delete the currently selected item in the tree.
/// Note this is not necessarilly the current ember, it's just the item
@ -275,25 +276,18 @@ void Fractorium::OnEmberTreeItemDoubleClicked(QTreeWidgetItem* item, int col) {
template <typename T>
void FractoriumEmberController<T>::Delete(const pair<size_t, QTreeWidgetItem*>& p)
{
auto tree = m_Fractorium->ui.LibraryTree;
tree->blockSignals(true);
if (m_EmberFile.Delete(p.first))
{
delete p.second;
SyncPointers();
SyncLibrary(eLibraryUpdate::INDEX);
}
tree->blockSignals(false);
//If there is now only one item left and it wasn't selected, select it.
if (auto top = tree->topLevelItem(0))
{
if (auto top = m_Fractorium->ui.LibraryTree->topLevelItem(0))
if (top->childCount() == 1)
if (auto item = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(0)))
if (item->GetEmber()->m_Name != m_Ember.m_Name)
EmberTreeItemDoubleClicked(top->child(0), 0);
}
}
/// <summary>
@ -326,7 +320,7 @@ void FractoriumEmberController<T>::RenderPreviews(uint start, uint end)
if (auto top = tree->topLevelItem(0))
{
int childCount = top->childCount();
vector<byte> emptyPreview(PREVIEW_SIZE * PREVIEW_SIZE * 3);
vector<byte> emptyPreview(PREVIEW_SIZE * PREVIEW_SIZE * 4);
for (int i = 0; i < childCount; i++)
if (auto treeItem = dynamic_cast<EmberTreeWidgetItem<T>*>(top->child(i)))

View File

@ -55,7 +55,6 @@ void FractoriumEmberController<T>::NewFlock(size_t count)
Ember<T> ember;
StopPreviewRender();
m_EmberFile.Clear();
m_EmberFile.m_Embers.reserve(count);
m_EmberFile.m_Filename = EmberFile<T>::DefaultFilename();
for (size_t i = 0; i < count; i++)
@ -206,7 +205,7 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(const QStringList& filenames
}
if (!errors.empty())
m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit);
m_Fractorium->ErrorReportToQTextEdit(errors, m_Fractorium->ui.InfoFileOpeningTextEdit, false);//Concat errors from all files.
}
if (append)
@ -216,12 +215,14 @@ void FractoriumEmberController<T>::OpenAndPrepFiles(const QStringList& filenames
m_EmberFile.m_Embers.insert(m_EmberFile.m_Embers.end(), emberFile.m_Embers.begin(), emberFile.m_Embers.end());
}
else
m_EmberFile = emberFile;
else if (emberFile.Size() > 0)//Ensure at least something was read.
m_EmberFile = std::move(emberFile);//Move the temp to avoid creating dupes because we no longer need it.
//Resync indices and names.
for (i = 0; i < m_EmberFile.Size(); i++)
m_EmberFile.m_Embers[i].m_Index = i;
i = 0;
for (auto& it : m_EmberFile.m_Embers)
it.m_Index = i++;
m_EmberFile.MakeNamesUnique();
@ -281,7 +282,7 @@ void FractoriumEmberController<T>::SaveCurrentAsXml()
if (tempEdit)
xmlFreeDoc(tempEdit);
if (writer.Save(filename.toStdString().c_str(), ember, 0, true, false, true))
if (writer.Save(filename.toStdString().c_str(), ember, 0, true, true))
{
s->SaveFolder(fileInfo.canonicalPath());
@ -324,7 +325,7 @@ void FractoriumEmberController<T>::SaveEntireFileAsXml()
for (auto& ember : emberFile.m_Embers)
ApplyXmlSavingTemplate(ember);
if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, false, true))
if (writer.Save(filename.toStdString().c_str(), emberFile.m_Embers, 0, true, true))
{
if (!s->SaveAutoUnique() || m_LastSaveAll == "")//Only save filename on first time through when doing auto unique names.
m_LastSaveAll = filename;
@ -349,7 +350,7 @@ void Fractorium::OnActionSaveCurrentScreen(bool checked)
auto& pixels = *m_Controller->FinalImage();
auto rendererCL = dynamic_cast<RendererCLBase*>(m_Controller->Renderer());
auto stats = m_Controller->Stats();
auto comments = renderer->ImageComments(stats, 0, false, true);
auto comments = renderer->ImageComments(stats, 0, true);
if (rendererCL && renderer->PrepFinalAccumVector(pixels))
{
@ -370,18 +371,19 @@ void Fractorium::OnActionSaveCurrentScreen(bool checked)
template <typename T>
void FractoriumEmberController<T>::SaveCurrentToOpenedFile()
{
uint i;
uint i = 0;
bool fileFound = false;
for (i = 0; i < m_EmberFile.Size(); i++)
for (auto& it : m_EmberFile.m_Embers)
{
if ((m_Ember.m_Name == m_EmberFile.m_Embers[i].m_Name) &&//Check both to be extra sure.
(m_Ember.m_Index == m_EmberFile.m_Embers[i].m_Index))
if (&it == m_EmberFilePointer)//Just compare memory addresses.
{
m_EmberFile.m_Embers[i] = m_Ember;
it = m_Ember;//Save it to the opened file in memory.
fileFound = true;
break;
}
i++;
}
if (!fileFound)
@ -470,7 +472,7 @@ void FractoriumEmberController<T>::CopyXml()
ember.m_Quality = settings->XmlQuality();
ember.m_Supersample = settings->XmlSupersample();
ember.m_TemporalSamples = settings->XmlTemporalSamples();
QApplication::clipboard()->setText(QString::fromStdString(emberToXml.ToString(ember, "", 0, false, false, true)));
QApplication::clipboard()->setText(QString::fromStdString(emberToXml.ToString(ember, "", 0, false, true)));
}
void Fractorium::OnActionCopyXml(bool checked) { m_Controller->CopyXml(); }
@ -490,7 +492,7 @@ void FractoriumEmberController<T>::CopyAllXml()
{
Ember<T> ember = e;
ApplyXmlSavingTemplate(ember);
os << emberToXml.ToString(ember, "", 0, false, false, true);
os << emberToXml.ToString(ember, "", 0, false, true);
}
os << "</flames>\n";
@ -563,9 +565,10 @@ void Fractorium::OnActionPasteXmlAppend(bool checked) { m_Controller->PasteXmlAp
template <typename T>
void FractoriumEmberController<T>::PasteXmlOver()
{
size_t i = 0;
string s, errors;
XmlToEmber<T> parser;
auto backupEmber = m_EmberFile.m_Embers[0];
auto backupEmber = m_EmberFile.m_Embers.begin();
auto codec = QTextCodec::codecForName("UTF-8");
auto b = codec->fromUnicode(QApplication::clipboard()->text());
s.reserve(b.size());
@ -589,20 +592,20 @@ void FractoriumEmberController<T>::PasteXmlOver()
if (m_EmberFile.Size())
{
for (auto i = 0; i < m_EmberFile.Size(); i++)
for (auto it : m_EmberFile.m_Embers)
{
m_EmberFile.m_Embers[i].m_Index = i;
ConstrainDimensions(m_EmberFile.m_Embers[i]);//Do not exceed the max texture size.
it.m_Index = i++;
ConstrainDimensions(it);//Do not exceed the max texture size.
//Also ensure it has a name.
if (m_EmberFile.m_Embers[i].m_Name == "" || m_EmberFile.m_Embers[i].m_Name == "No name")
m_EmberFile.m_Embers[i].m_Name = ToString<qulonglong>(m_EmberFile.m_Embers[i].m_Index).toStdString();
if (it.m_Name == "" || it.m_Name == "No name")
it.m_Name = ToString<qulonglong>(it.m_Index).toStdString();
}
}
else
{
backupEmber.m_Index = 0;
m_EmberFile.m_Embers.push_back(backupEmber);
backupEmber->m_Index = 0;
m_EmberFile.m_Embers.push_back(*backupEmber);
}
m_EmberFile.MakeNamesUnique();

View File

@ -11,12 +11,6 @@ GLWidget::GLWidget(QWidget* p)
: QOpenGLWidget(p)
{
QSurfaceFormat qsf;
m_Init = false;
m_Drawing = false;
m_TexWidth = 0;
m_TexHeight = 0;
m_OutputTexID = 0;
m_Fractorium = nullptr;
qsf.setSwapInterval(1);//Vsync.
qsf.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
qsf.setVersion(2, 0);

View File

@ -73,13 +73,13 @@ private:
void DrawAffineHelper(int index, bool selected, bool pre, bool final, bool background);
GLEmberControllerBase* GLController();
bool m_Init;
bool m_Drawing;
GLint m_MaxTexSize;
GLint m_TexWidth;
GLint m_TexHeight;
GLint m_ViewWidth;
GLint m_ViewHeight;
GLuint m_OutputTexID;
Fractorium* m_Fractorium;
bool m_Init = false;
bool m_Drawing = false;
GLint m_MaxTexSize = 16384;
GLint m_TexWidth = 0;
GLint m_TexHeight = 0;
GLint m_ViewWidth = 0;
GLint m_ViewHeight = 0;
GLuint m_OutputTexID = 0;
Fractorium* m_Fractorium = nullptr;
};

View File

@ -0,0 +1,40 @@
#include "FractoriumPch.h"
#include "LibraryTreeWidget.h"
#include "Fractorium.h"
/// <summary>
/// Set a pointer to the main window.
/// </summary>
/// <param name="f">Pointer to the main Fractorium object</param>
void LibraryTreeWidget::SetMainWindow(Fractorium* f)
{
m_Fractorium = f;
}
/// <summary>
/// Process the drop event to allow for moving items around inside of the tree.
/// </summary>
/// <param name="de">Pointer to the QDropEvent object</param>
void LibraryTreeWidget::dropEvent(QDropEvent* de)
{
QModelIndex droppedIndex = indexAt(de->pos());
auto items = selectionModel()->selectedIndexes();
if (!droppedIndex.isValid())//Don't process drop because it's outside of the droppable area.
{
de->ignore();
return;
}
else if (!items.empty())//Actually do the drop and move the item to a new location.
{
int row = droppedIndex.row();
DropIndicatorPosition dp = dropIndicatorPosition();
if (dp == QAbstractItemView::BelowItem)
row++;
m_Fractorium->m_Controller->MoveLibraryItems(items[0].row(), row);
}
QTreeWidget::dropEvent(de);
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "FractoriumPch.h"
class Fractorium;
/// <summary>
/// A thin derivation of QTreeWidget which allows for processing the drop event.
/// </summary>
class LibraryTreeWidget : public QTreeWidget
{
Q_OBJECT
public:
/// <summary>
/// Constructor that passes p to the parent.
/// </summary>
/// <param name="p">The parent widget</param>
explicit LibraryTreeWidget(QWidget* p = nullptr)
: QTreeWidget(p)
{
}
void SetMainWindow(Fractorium* f);
protected:
virtual void dropEvent(QDropEvent* de) override;
Fractorium* m_Fractorium = nullptr;
};

View File

@ -24,7 +24,7 @@ class FractoriumOptionsDialog : public QDialog
friend Fractorium;
public:
FractoriumOptionsDialog(FractoriumSettings* settings, QWidget* p = 0, Qt::WindowFlags f = 0);
FractoriumOptionsDialog(FractoriumSettings* settings, QWidget* p = nullptr, Qt::WindowFlags f = 0);
public slots:
void OnOpenCLCheckBoxStateChanged(int state);

View File

@ -16,7 +16,7 @@ class SpinBox : public QSpinBox
Q_OBJECT
public:
explicit SpinBox(QWidget* p = 0, int height = 16, int step = 1);
explicit SpinBox(QWidget* p = nullptr, int height = 16, int step = 1);
virtual ~SpinBox() { }
void SetValueStealth(int d);
void SetValueStealth(size_t d);

View File

@ -15,8 +15,8 @@ class StealthComboBox : public QComboBox
Q_OBJECT
public:
explicit StealthComboBox(QWidget* p = 0) : QComboBox(p) { }
explicit StealthComboBox(QWidget* p = nullptr) : QComboBox(p) { }
/// <summary>
/// Set the current index of the combo box without triggering signals.
/// </summary>

View File

@ -24,14 +24,14 @@
/// </summary>
class TableWidget : public QTableWidget
{
Q_OBJECT
Q_OBJECT
public:
/// <summary>
/// Constructor that passes the parent to the base and installs
/// the event filter.
/// </summary>
/// <param name="p">The parent widget</param>
explicit TableWidget(QWidget* p = 0)
explicit TableWidget(QWidget* p = nullptr)
: QTableWidget(p)
{
viewport()->installEventFilter(this);
@ -46,7 +46,7 @@ protected:
/// <returns>True if mouse wheel, else return the result of calling the base fucntion.</returns>
bool eventFilter(QObject* obj, QEvent* e)
{
if(e->type() == QEvent::Wheel)
if (e->type() == QEvent::Wheel)
{
e->ignore();
return true;

View File

@ -22,7 +22,7 @@ public:
/// </summary>
/// <param name="id">The ID of the variation this widget will represent</param>
/// <param name="p">The parent widget</param>
VariationTreeWidgetItem(eVariationId id, QTreeWidget* p = 0)
VariationTreeWidgetItem(eVariationId id, QTreeWidget* p = nullptr)
: QTreeWidgetItem(p)
{
m_Id = id;