mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-01-21 13:10:04 -05:00
--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:
parent
124f807772
commit
b690bf8071
@ -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" />
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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" />
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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().
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#ifdef __APPLE__
|
||||
#include <malloc/malloc.h>
|
||||
#else
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) << "%)";
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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>();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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 = ⁢
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)))
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
40
Source/Fractorium/LibraryTreeWidget.cpp
Normal file
40
Source/Fractorium/LibraryTreeWidget.cpp
Normal 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);
|
||||
}
|
29
Source/Fractorium/LibraryTreeWidget.h
Normal file
29
Source/Fractorium/LibraryTreeWidget.h
Normal 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;
|
||||
};
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user