mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-02-01 18:40:12 -05:00
0.4.1.8 Beta - Date pending testing.
--User changes Thread image writing in EmberAnimate and when doing animation sequence in final render dialog. Add total time output for verbose mode in EmberAnimate to match EmberRender. --Bug Fixes Fix incorrect iters ran/requested percentage in EmberAnimate to match EmberRender. Fix motion blur being disabled when doing animations in final render dialog. Allow for boolean command line options which default to true to be set to false. --Code Changes Minor changes to enable a Mac build. Double the memory required for the final output buffer in RendererBase::MemoryRequired() when threading image writing. Reuse same buffer for RgbaToRgb() in EmberRender and EmberAnimate. Only resize in RgbaToRgb() if the two vectors are not the same. Add a final output buffer ping-ponging mechanism to facilitate threaded writes in controllers.
This commit is contained in:
parent
2999cd159f
commit
4059767dc4
@ -6,7 +6,7 @@
|
|||||||
<ProductVersion>3.7</ProductVersion>
|
<ProductVersion>3.7</ProductVersion>
|
||||||
<ProjectGuid>{c8096c47-e358-438c-a520-146d46b0637d}</ProjectGuid>
|
<ProjectGuid>{c8096c47-e358-438c-a520-146d46b0637d}</ProjectGuid>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<OutputName>Fractorium_Beta_0.4.1.7</OutputName>
|
<OutputName>Fractorium_Beta_0.4.1.8</OutputName>
|
||||||
<OutputType>Package</OutputType>
|
<OutputType>Package</OutputType>
|
||||||
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
||||||
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
<?define ProductVersion="0.4.1.7" ?>
|
<?define ProductVersion="0.4.1.8" ?>
|
||||||
<?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?>
|
<?define ProductName="Fractorium Beta $(var.ProductVersion) ($(var.GpuType))" ?>
|
||||||
<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?>
|
<?define UpgradeCode="{4714cd15-bfba-44f6-8059-9e1466ebfa6e}"?>
|
||||||
<?define Manufacturer="Fractorium"?>
|
<?define Manufacturer="Fractorium"?>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<!--
|
<!--
|
||||||
Change this for every release.
|
Change this for every release.
|
||||||
-->
|
-->
|
||||||
<?define ProductCode="{20639B5F-7EF0-4708-8746-321466EECD84}"?>
|
<?define ProductCode="{1992CA14-0611-4980-95B8-1347161BD9EC}"?>
|
||||||
|
|
||||||
<Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
<Product Id="$(var.ProductCode)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
|
||||||
<Package
|
<Package
|
||||||
|
@ -1,3 +1,20 @@
|
|||||||
|
0.4.1.8 Beta
|
||||||
|
--User changes
|
||||||
|
Thread image writing in EmberAnimate and when doing animation sequence in final render dialog.
|
||||||
|
Add total time output for verbose mode in EmberAnimate to match EmberRender.
|
||||||
|
|
||||||
|
--Bug Fixes
|
||||||
|
Fix incorrect iters ran/requested percentage in EmberAnimate to match EmberRender.
|
||||||
|
Fix motion blur being disabled when doing animations in final render dialog.
|
||||||
|
Allow for boolean command line options which default to true to be set to false.
|
||||||
|
|
||||||
|
--Code Changes
|
||||||
|
Minor changes to enable a Mac build.
|
||||||
|
Double the memory required for the final output buffer in RendererBase::MemoryRequired() when threading image writing.
|
||||||
|
Reuse same buffer for RgbaToRgb() in EmberRender and EmberAnimate.
|
||||||
|
Only resize in RgbaToRgb() if the two vectors are not the same.
|
||||||
|
Add a final output buffer ping-ponging mechanism to facilitate threaded writes in controllers.
|
||||||
|
|
||||||
0.4.1.7 Beta 01/02/2015
|
0.4.1.7 Beta 01/02/2015
|
||||||
--User changes
|
--User changes
|
||||||
Use actual strips count when computing memory requirements in the final render dialog.
|
Use actual strips count when computing memory requirements in the final render dialog.
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
namespace EmberNs
|
namespace EmberNs
|
||||||
{
|
{
|
||||||
#define EMBER_VERSION "0.4.1.7"
|
#define EMBER_VERSION "0.4.1.8"
|
||||||
#define EPS6 T(1e-6)
|
#define EPS6 T(1e-6)
|
||||||
#define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way.
|
#define EPS std::numeric_limits<T>::epsilon()//Apoplugin.h uses -20, but it's more mathematically correct to do it this way.
|
||||||
#define ISAAC_SIZE 4
|
#define ISAAC_SIZE 4
|
||||||
|
@ -136,15 +136,21 @@ size_t RendererBase::HistMemoryRequired(size_t strips)
|
|||||||
/// Return a pair whose first member contains the amount of memory needed for the histogram,
|
/// Return a pair whose first member contains the amount of memory needed for the histogram,
|
||||||
/// and whose second member contains the total the amount of memory needed to render the current ember.
|
/// and whose second member contains the total the amount of memory needed to render the current ember.
|
||||||
/// Optionally include the memory needed for the final output image in pair.second.
|
/// Optionally include the memory needed for the final output image in pair.second.
|
||||||
|
/// Note that the memory required for the final output image will be doubled if threaded writes
|
||||||
|
/// are used because a copy of the final output is passed to a thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="strips">The number of strips being used</param>
|
||||||
/// <param name="includeFinal">If true include the memory needed for the final output image, else don't.</param>
|
/// <param name="includeFinal">If true include the memory needed for the final output image, else don't.</param>
|
||||||
|
/// <param name="threadedWrite">Whether the caller will be writing the output in a thread, which doubles the memory required for the final output buffer.</param>
|
||||||
/// <returns>The histogram memory required in first, and the total memory required in second</returns>
|
/// <returns>The histogram memory required in first, and the total memory required in second</returns>
|
||||||
pair<size_t, size_t> RendererBase::MemoryRequired(size_t strips, bool includeFinal)
|
pair<size_t, size_t> RendererBase::MemoryRequired(size_t strips, bool includeFinal, bool threadedWrite)
|
||||||
{
|
{
|
||||||
pair<size_t, size_t> p;
|
pair<size_t, size_t> p;
|
||||||
|
size_t outSize = includeFinal ? FinalBufferSize() : 0;
|
||||||
|
|
||||||
|
outSize *= (threadedWrite ? 2 : 1);
|
||||||
p.first = HistMemoryRequired(strips);
|
p.first = HistMemoryRequired(strips);
|
||||||
p.second = (p.first * 2) + (includeFinal ? FinalBufferSize() : 0);//Multiply hist by 2 to account for the density filtering buffer which is the same size as the histogram.
|
p.second = (p.first * 2) + outSize;//Multiply hist by 2 to account for the density filtering buffer which is the same size as the histogram.
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ public:
|
|||||||
//Non-virtual processing functions.
|
//Non-virtual processing functions.
|
||||||
void ChangeVal(std::function<void(void)> func, eProcessAction action);
|
void ChangeVal(std::function<void(void)> func, eProcessAction action);
|
||||||
size_t HistMemoryRequired(size_t strips);
|
size_t HistMemoryRequired(size_t strips);
|
||||||
pair<size_t, size_t> MemoryRequired(size_t strips, bool includeFinal);
|
pair<size_t, size_t> MemoryRequired(size_t strips, bool includeFinal, bool threadedWrite);
|
||||||
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> RandVec();
|
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> RandVec();
|
||||||
bool PrepFinalAccumVector(vector<byte>& pixels);
|
bool PrepFinalAccumVector(vector<byte>& pixels);
|
||||||
|
|
||||||
|
@ -28,15 +28,13 @@ bool EmberAnimate(EmberOptions& opt)
|
|||||||
//Regular variables.
|
//Regular variables.
|
||||||
Timing t;
|
Timing t;
|
||||||
bool unsorted = false;
|
bool unsorted = false;
|
||||||
bool writeSuccess = false;
|
|
||||||
bool startXml = false;
|
bool startXml = false;
|
||||||
bool finishXml = false;
|
bool finishXml = false;
|
||||||
bool appendXml = false;
|
bool appendXml = false;
|
||||||
byte* finalImagep;
|
uint finalImageIndex = 0;
|
||||||
uint i, channels, ftime;
|
uint i, channels, ftime;
|
||||||
string s, flameName, filename, inputPath = GetPath(opt.Input());
|
string s, flameName, filename, inputPath = GetPath(opt.Input());
|
||||||
ostringstream os;
|
ostringstream os;
|
||||||
vector<byte> finalImage, vecRgb;
|
|
||||||
vector<Ember<T>> embers;
|
vector<Ember<T>> embers;
|
||||||
EmberStats stats;
|
EmberStats stats;
|
||||||
EmberReport emberReport;
|
EmberReport emberReport;
|
||||||
@ -44,6 +42,8 @@ bool EmberAnimate(EmberOptions& opt)
|
|||||||
Ember<T> centerEmber;
|
Ember<T> centerEmber;
|
||||||
XmlToEmber<T> parser;
|
XmlToEmber<T> parser;
|
||||||
EmberToXml<T> emberToXml;
|
EmberToXml<T> emberToXml;
|
||||||
|
vector<byte> finalImages[2];
|
||||||
|
std::thread writeThread;
|
||||||
unique_ptr<RenderProgress<T>> progress(new RenderProgress<T>());
|
unique_ptr<RenderProgress<T>> progress(new RenderProgress<T>());
|
||||||
unique_ptr<Renderer<T, bucketT>> renderer(CreateRenderer<T, bucketT>(opt.EmberCL() ? OPENCL_RENDERER : CPU_RENDERER, opt.Platform(), opt.Device(), false, 0, emberReport));
|
unique_ptr<Renderer<T, bucketT>> renderer(CreateRenderer<T, bucketT>(opt.EmberCL() ? OPENCL_RENDERER : CPU_RENDERER, opt.Platform(), opt.Device(), false, 0, emberReport));
|
||||||
vector<string> errorReport = emberReport.ErrorReport();
|
vector<string> errorReport = emberReport.ErrorReport();
|
||||||
@ -259,6 +259,27 @@ bool EmberAnimate(EmberOptions& opt)
|
|||||||
renderer->BytesPerChannel(opt.BitsPerChannel() / 8);
|
renderer->BytesPerChannel(opt.BitsPerChannel() / 8);
|
||||||
renderer->Callback(opt.DoProgress() ? progress.get() : nullptr);
|
renderer->Callback(opt.DoProgress() ? progress.get() : nullptr);
|
||||||
|
|
||||||
|
std::function<void(uint)> saveFunc = [&](uint threadVecIndex)
|
||||||
|
{
|
||||||
|
bool writeSuccess = false;
|
||||||
|
byte* finalImagep = finalImages[threadVecIndex].data();
|
||||||
|
|
||||||
|
if ((opt.Format() == "jpg" || opt.Format() == "bmp") && renderer->NumChannels() == 4)
|
||||||
|
RgbaToRgb(finalImages[threadVecIndex], finalImages[threadVecIndex], renderer->FinalRasW(), renderer->FinalRasH());
|
||||||
|
|
||||||
|
if (opt.Format() == "png")
|
||||||
|
writeSuccess = WritePng(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH(), opt.BitsPerChannel() / 8, opt.PngComments(), comments, opt.Id(), opt.Url(), opt.Nick());
|
||||||
|
else if (opt.Format() == "jpg")
|
||||||
|
writeSuccess = WriteJpeg(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH(), opt.JpegQuality(), opt.JpegComments(), comments, opt.Id(), opt.Url(), opt.Nick());
|
||||||
|
else if (opt.Format() == "ppm")
|
||||||
|
writeSuccess = WritePpm(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH());
|
||||||
|
else if (opt.Format() == "bmp")
|
||||||
|
writeSuccess = WriteBmp(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH());
|
||||||
|
|
||||||
|
if (!writeSuccess)
|
||||||
|
cout << "Error writing " << filename << endl;/**/
|
||||||
|
};
|
||||||
|
|
||||||
//Begin run.
|
//Begin run.
|
||||||
for (ftime = opt.FirstFrame(); ftime <= opt.LastFrame(); ftime += opt.Dtime())
|
for (ftime = opt.FirstFrame(); ftime <= opt.LastFrame(); ftime += opt.Dtime())
|
||||||
{
|
{
|
||||||
@ -269,7 +290,7 @@ bool EmberAnimate(EmberOptions& opt)
|
|||||||
|
|
||||||
renderer->Reset();
|
renderer->Reset();
|
||||||
|
|
||||||
if ((renderer->Run(finalImage, localTime) != RENDER_OK) || renderer->Aborted() || finalImage.empty())
|
if ((renderer->Run(finalImages[finalImageIndex], localTime) != RENDER_OK) || renderer->Aborted() || finalImages[finalImageIndex].empty())
|
||||||
{
|
{
|
||||||
cout << "Error: image rendering failed, skipping to next image." << endl;
|
cout << "Error: image rendering failed, skipping to next image." << endl;
|
||||||
renderer->DumpErrorReport();//Something went wrong, print errors.
|
renderer->DumpErrorReport();//Something went wrong, print errors.
|
||||||
@ -298,12 +319,11 @@ bool EmberAnimate(EmberOptions& opt)
|
|||||||
emberToXml.Save(flameName, centerEmber, opt.PrintEditDepth(), true, opt.IntPalette(), opt.HexPalette(), true, startXml, finishXml);
|
emberToXml.Save(flameName, centerEmber, opt.PrintEditDepth(), true, opt.IntPalette(), opt.HexPalette(), true, startXml, finishXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSuccess = false;
|
|
||||||
stats = renderer->Stats();
|
stats = renderer->Stats();
|
||||||
comments = renderer->ImageComments(stats, opt.PrintEditDepth(), opt.IntPalette(), opt.HexPalette());
|
comments = renderer->ImageComments(stats, opt.PrintEditDepth(), opt.IntPalette(), opt.HexPalette());
|
||||||
os.str("");
|
os.str("");
|
||||||
size_t iterCount = renderer->TotalIterCount(1);
|
size_t iterCount = renderer->TotalIterCount(1);
|
||||||
os << comments.m_NumIters << " / " << iterCount << " (" << std::fixed << std::setprecision(2) << double(stats.m_Iters) / double(iterCount * 100) << "%)";
|
os << comments.m_NumIters << " / " << iterCount << " (" << std::fixed << std::setprecision(2) << ((double(stats.m_Iters) / double(iterCount)) * 100) << "%)";
|
||||||
|
|
||||||
VerbosePrint("\nIters ran/requested: " + os.str());
|
VerbosePrint("\nIters ran/requested: " + os.str());
|
||||||
VerbosePrint("Bad values: " << stats.m_Badvals);
|
VerbosePrint("Bad values: " << stats.m_Badvals);
|
||||||
@ -312,33 +332,30 @@ bool EmberAnimate(EmberOptions& opt)
|
|||||||
VerbosePrint("Iters/sec: " << size_t(stats.m_Iters / (stats.m_IterMs / 1000.0)) << endl);
|
VerbosePrint("Iters/sec: " << size_t(stats.m_Iters / (stats.m_IterMs / 1000.0)) << endl);
|
||||||
VerbosePrint("Writing " + filename);
|
VerbosePrint("Writing " + filename);
|
||||||
|
|
||||||
if ((opt.Format() == "jpg" || opt.Format() == "bmp") && renderer->NumChannels() == 4)
|
//Run image writing in a thread. Although doing it this way duplicates the final output memory, it saves a lot of time
|
||||||
{
|
//when running with OpenCL. Call join() to ensure the previous thread call has completed.
|
||||||
RgbaToRgb(finalImage, vecRgb, renderer->FinalRasW(), renderer->FinalRasH());
|
if (writeThread.joinable())
|
||||||
|
writeThread.join();
|
||||||
|
|
||||||
finalImagep = vecRgb.data();
|
uint threadVecIndex = finalImageIndex;//Cache before launching thread.
|
||||||
}
|
|
||||||
|
if (opt.ThreadedWrite())
|
||||||
|
writeThread = std::thread(saveFunc, threadVecIndex);
|
||||||
else
|
else
|
||||||
{
|
saveFunc(threadVecIndex);
|
||||||
finalImagep = finalImage.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt.Format() == "png")
|
|
||||||
writeSuccess = WritePng(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH(), opt.BitsPerChannel() / 8, opt.PngComments(), comments, opt.Id(), opt.Url(), opt.Nick());
|
|
||||||
else if (opt.Format() == "jpg")
|
|
||||||
writeSuccess = WriteJpeg(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH(), opt.JpegQuality(), opt.JpegComments(), comments, opt.Id(), opt.Url(), opt.Nick());
|
|
||||||
else if (opt.Format() == "ppm")
|
|
||||||
writeSuccess = WritePpm(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH());
|
|
||||||
else if (opt.Format() == "bmp")
|
|
||||||
writeSuccess = WriteBmp(filename.c_str(), finalImagep, renderer->FinalRasW(), renderer->FinalRasH());
|
|
||||||
|
|
||||||
if (!writeSuccess)
|
|
||||||
cout << "Error writing " << filename << endl;
|
|
||||||
|
|
||||||
centerEmber.Clear();
|
centerEmber.Clear();
|
||||||
|
finalImageIndex ^= 1;//Toggle the index.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (writeThread.joinable())
|
||||||
|
writeThread.join();
|
||||||
|
|
||||||
VerbosePrint("Done.\n");
|
VerbosePrint("Done.\n");
|
||||||
|
|
||||||
|
if (opt.Verbose())
|
||||||
|
t.Toc("\nTotal time: ", true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,4,1,7
|
FILEVERSION 0,4,1,8
|
||||||
PRODUCTVERSION 0,4,1,7
|
PRODUCTVERSION 0,4,1,8
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -67,12 +67,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Open Source"
|
VALUE "CompanyName", "Open Source"
|
||||||
VALUE "FileDescription", "Renders fractal flames as animations with motion blur"
|
VALUE "FileDescription", "Renders fractal flames as animations with motion blur"
|
||||||
VALUE "FileVersion", "0.4.1.7"
|
VALUE "FileVersion", "0.4.1.8"
|
||||||
VALUE "InternalName", "EmberAnimate.rc"
|
VALUE "InternalName", "EmberAnimate.rc"
|
||||||
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
|
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
|
||||||
VALUE "OriginalFilename", "EmberAnimate.rc"
|
VALUE "OriginalFilename", "EmberAnimate.rc"
|
||||||
VALUE "ProductName", "Ember Animate"
|
VALUE "ProductName", "Ember Animate"
|
||||||
VALUE "ProductVersion", "0.4.1.7"
|
VALUE "ProductVersion", "0.4.1.8"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -124,6 +124,7 @@ static bool InitPaletteList(const string& filename)
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert an RGBA buffer to an RGB buffer.
|
/// Convert an RGBA buffer to an RGB buffer.
|
||||||
|
/// The two buffers can point to the same memory location if needed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rgba">The RGBA buffer</param>
|
/// <param name="rgba">The RGBA buffer</param>
|
||||||
/// <param name="rgb">The RGB buffer</param>
|
/// <param name="rgb">The RGB buffer</param>
|
||||||
@ -131,7 +132,8 @@ static bool InitPaletteList(const string& filename)
|
|||||||
/// <param name="height">The height of the image in pixels</param>
|
/// <param name="height">The height of the image in pixels</param>
|
||||||
static void RgbaToRgb(vector<byte>& rgba, vector<byte>& rgb, size_t width, size_t height)
|
static void RgbaToRgb(vector<byte>& rgba, vector<byte>& rgb, size_t width, size_t height)
|
||||||
{
|
{
|
||||||
rgb.resize(width * height * 3);
|
if (rgba.data() != rgb.data())//Only resize the destination buffer if they are different.
|
||||||
|
rgb.resize(width * height * 3);
|
||||||
|
|
||||||
for (uint i = 0, j = 0; i < (width * height * 4); i += 4, j += 3)
|
for (uint i = 0, j = 0; i < (width * height * 4); i += 4, j += 3)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,7 @@ enum eOptionIDs
|
|||||||
OPT_JPEG_COMMENTS,
|
OPT_JPEG_COMMENTS,
|
||||||
OPT_PNG_COMMENTS,
|
OPT_PNG_COMMENTS,
|
||||||
OPT_WRITE_GENOME,
|
OPT_WRITE_GENOME,
|
||||||
|
OPT_THREADED_WRITE,
|
||||||
OPT_ENCLOSED,
|
OPT_ENCLOSED,
|
||||||
OPT_NO_EDITS,
|
OPT_NO_EDITS,
|
||||||
OPT_UNSMOOTH_EDGE,
|
OPT_UNSMOOTH_EDGE,
|
||||||
@ -176,11 +177,29 @@ public:
|
|||||||
*this = entry;
|
*this = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default assignment operator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entry">The EmberOptionEntry object to copy</param>
|
||||||
|
EmberOptionEntry<T>& operator = (const EmberOptionEntry<T>& entry)
|
||||||
|
{
|
||||||
|
if (this != &entry)
|
||||||
|
{
|
||||||
|
m_OptionUse = entry.m_OptionUse;
|
||||||
|
m_Option = entry.m_Option;
|
||||||
|
m_DocString = entry.m_DocString;
|
||||||
|
m_NameWithoutDashes = entry.m_NameWithoutDashes;
|
||||||
|
m_Val = entry.m_Val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Functor accessors.
|
/// Functor accessors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
inline T operator() (void) { return m_Val; }
|
inline T operator() (void) { return m_Val; }
|
||||||
inline void operator() (T t) { m_Val = t; }
|
inline void operator() (T t) { m_Val = t; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
eOptionUse m_OptionUse;
|
eOptionUse m_OptionUse;
|
||||||
@ -202,7 +221,16 @@ private:
|
|||||||
|
|
||||||
#define PARSEBOOLOPTION(opt, member) \
|
#define PARSEBOOLOPTION(opt, member) \
|
||||||
case (opt): \
|
case (opt): \
|
||||||
member(true); \
|
{ \
|
||||||
|
if (member.m_Option.nArgType == SO_OPT) \
|
||||||
|
{ \
|
||||||
|
member(!strcmp(args.OptionArg(), "true")); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
member(true); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
break
|
break
|
||||||
|
|
||||||
//Int.
|
//Int.
|
||||||
@ -284,12 +312,13 @@ public:
|
|||||||
INITBOOLOPTION(Transparency, Eob(OPT_USE_ALL, OPT_TRANSPARENCY, _T("--transparency"), false, SO_NONE, "\t--transparency Include alpha channel in final output [default: false except for PNG].\n"));
|
INITBOOLOPTION(Transparency, Eob(OPT_USE_ALL, OPT_TRANSPARENCY, _T("--transparency"), false, SO_NONE, "\t--transparency Include alpha channel in final output [default: false except for PNG].\n"));
|
||||||
INITBOOLOPTION(NameEnable, Eob(OPT_USE_RENDER, 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(NameEnable, Eob(OPT_USE_RENDER, 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(OPT_RENDER_ANIM, OPT_INT_PALETTE, _T("--intpalette"), false, SO_NONE, "\t--intpalette Force palette RGB values to be integers [default: false (float)].\n"));
|
INITBOOLOPTION(IntPalette, Eob(OPT_RENDER_ANIM, OPT_INT_PALETTE, _T("--intpalette"), false, SO_NONE, "\t--intpalette Force palette RGB values to be integers [default: false (float)].\n"));
|
||||||
INITBOOLOPTION(HexPalette, Eob(OPT_USE_ALL, OPT_HEX_PALETTE, _T("--hex_palette"), true, SO_NONE, "\t--hex_palette Force palette RGB values to be hex [default: true].\n"));
|
INITBOOLOPTION(HexPalette, Eob(OPT_USE_ALL, 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(OPT_RENDER_ANIM, 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(InsertPalette, Eob(OPT_RENDER_ANIM, 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(OPT_RENDER_ANIM, OPT_JPEG_COMMENTS, _T("--enable_jpeg_comments"), true, SO_NONE, "\t--enable_jpeg_comments Enables comments in the jpeg header [default: true].\n"));
|
INITBOOLOPTION(JpegComments, Eob(OPT_RENDER_ANIM, 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(OPT_RENDER_ANIM, OPT_PNG_COMMENTS, _T("--enable_png_comments"), true, SO_NONE, "\t--enable_png_comments Enables comments in the png header [default: true].\n"));
|
INITBOOLOPTION(PngComments, Eob(OPT_RENDER_ANIM, 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(OPT_USE_ANIMATE, 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(WriteGenome, Eob(OPT_USE_ANIMATE, 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(Enclosed, Eob(OPT_USE_GENOME, OPT_ENCLOSED, _T("--enclosed"), true, SO_NONE, "\t--enclosed Use enclosing XML tags [default: false].\n"));
|
INITBOOLOPTION(ThreadedWrite, Eob(OPT_RENDER_ANIM, OPT_THREADED_WRITE, _T("--threaded_write"), true, SO_OPT, "\t--threaded_write Use a separate thread to write images to disk. This doubles the memory required for the final output buffer. [default: true].\n"));
|
||||||
|
INITBOOLOPTION(Enclosed, Eob(OPT_USE_GENOME, OPT_ENCLOSED, _T("--enclosed"), true, SO_OPT, "\t--enclosed Use enclosing XML tags [default: true].\n"));
|
||||||
INITBOOLOPTION(NoEdits, Eob(OPT_USE_GENOME, OPT_NO_EDITS, _T("--noedits"), false, SO_NONE, "\t--noedits Exclude edit tags when writing Xml [default: false].\n"));
|
INITBOOLOPTION(NoEdits, Eob(OPT_USE_GENOME, OPT_NO_EDITS, _T("--noedits"), false, SO_NONE, "\t--noedits Exclude edit tags when writing Xml [default: false].\n"));
|
||||||
INITBOOLOPTION(UnsmoothEdge, Eob(OPT_USE_GENOME, OPT_UNSMOOTH_EDGE, _T("--unsmoother"), false, SO_NONE, "\t--unsmoother Do not use smooth blending for sheep edges [default: false].\n"));
|
INITBOOLOPTION(UnsmoothEdge, Eob(OPT_USE_GENOME, OPT_UNSMOOTH_EDGE, _T("--unsmoother"), false, SO_NONE, "\t--unsmoother Do not use smooth blending for sheep edges [default: false].\n"));
|
||||||
INITBOOLOPTION(LockAccum, Eob(OPT_USE_ALL, 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"));
|
INITBOOLOPTION(LockAccum, Eob(OPT_USE_ALL, 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"));
|
||||||
@ -422,6 +451,7 @@ public:
|
|||||||
PARSEBOOLOPTION(OPT_JPEG_COMMENTS, JpegComments);
|
PARSEBOOLOPTION(OPT_JPEG_COMMENTS, JpegComments);
|
||||||
PARSEBOOLOPTION(OPT_PNG_COMMENTS, PngComments);
|
PARSEBOOLOPTION(OPT_PNG_COMMENTS, PngComments);
|
||||||
PARSEBOOLOPTION(OPT_WRITE_GENOME, WriteGenome);
|
PARSEBOOLOPTION(OPT_WRITE_GENOME, WriteGenome);
|
||||||
|
PARSEBOOLOPTION(OPT_THREADED_WRITE, ThreadedWrite);
|
||||||
PARSEBOOLOPTION(OPT_ENCLOSED, Enclosed);
|
PARSEBOOLOPTION(OPT_ENCLOSED, Enclosed);
|
||||||
PARSEBOOLOPTION(OPT_NO_EDITS, NoEdits);
|
PARSEBOOLOPTION(OPT_NO_EDITS, NoEdits);
|
||||||
PARSEBOOLOPTION(OPT_UNSMOOTH_EDGE, UnsmoothEdge);
|
PARSEBOOLOPTION(OPT_UNSMOOTH_EDGE, UnsmoothEdge);
|
||||||
@ -636,6 +666,7 @@ public:
|
|||||||
EmberOptionEntry<bool> JpegComments;
|
EmberOptionEntry<bool> JpegComments;
|
||||||
EmberOptionEntry<bool> PngComments;
|
EmberOptionEntry<bool> PngComments;
|
||||||
EmberOptionEntry<bool> WriteGenome;
|
EmberOptionEntry<bool> WriteGenome;
|
||||||
|
EmberOptionEntry<bool> ThreadedWrite;
|
||||||
EmberOptionEntry<bool> Enclosed;
|
EmberOptionEntry<bool> Enclosed;
|
||||||
EmberOptionEntry<bool> NoEdits;
|
EmberOptionEntry<bool> NoEdits;
|
||||||
EmberOptionEntry<bool> UnsmoothEdge;
|
EmberOptionEntry<bool> UnsmoothEdge;
|
||||||
|
@ -49,8 +49,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,4,1,7
|
FILEVERSION 0,4,1,8
|
||||||
PRODUCTVERSION 0,4,1,7
|
PRODUCTVERSION 0,4,1,8
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -67,12 +67,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Open Source"
|
VALUE "CompanyName", "Open Source"
|
||||||
VALUE "FileDescription", "Manipulates fractal flames parameter files"
|
VALUE "FileDescription", "Manipulates fractal flames parameter files"
|
||||||
VALUE "FileVersion", "0.4.1.7"
|
VALUE "FileVersion", "0.4.1.8"
|
||||||
VALUE "InternalName", "EmberGenome.rc"
|
VALUE "InternalName", "EmberGenome.rc"
|
||||||
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
|
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
|
||||||
VALUE "OriginalFilename", "EmberGenome.rc"
|
VALUE "OriginalFilename", "EmberGenome.rc"
|
||||||
VALUE "ProductName", "Ember Genome"
|
VALUE "ProductName", "Ember Genome"
|
||||||
VALUE "ProductVersion", "0.4.1.7"
|
VALUE "ProductVersion", "0.4.1.8"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -36,7 +36,7 @@ bool EmberRender(EmberOptions& opt)
|
|||||||
ostringstream os;
|
ostringstream os;
|
||||||
pair<size_t, size_t> p;
|
pair<size_t, size_t> p;
|
||||||
vector<Ember<T>> embers;
|
vector<Ember<T>> embers;
|
||||||
vector<byte> finalImage, vecRgb;
|
vector<byte> finalImage;
|
||||||
EmberStats stats;
|
EmberStats stats;
|
||||||
EmberReport emberReport;
|
EmberReport emberReport;
|
||||||
EmberImageComments comments;
|
EmberImageComments comments;
|
||||||
@ -202,7 +202,7 @@ bool EmberRender(EmberOptions& opt)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = renderer->MemoryRequired(1, true);
|
p = renderer->MemoryRequired(1, true, false);//No threaded write for render, only for animate.
|
||||||
strips = CalcStrips(double(p.second), double(renderer->MemoryAvailable()), opt.UseMem());
|
strips = CalcStrips(double(p.second), double(renderer->MemoryAvailable()), opt.UseMem());
|
||||||
|
|
||||||
if (strips > 1)
|
if (strips > 1)
|
||||||
@ -280,16 +280,9 @@ bool EmberRender(EmberOptions& opt)
|
|||||||
VerbosePrint("Writing " + filename);
|
VerbosePrint("Writing " + filename);
|
||||||
|
|
||||||
if ((opt.Format() == "jpg" || opt.Format() == "bmp") && renderer->NumChannels() == 4)
|
if ((opt.Format() == "jpg" || opt.Format() == "bmp") && renderer->NumChannels() == 4)
|
||||||
{
|
RgbaToRgb(finalImage, finalImage, renderer->FinalRasW(), renderer->FinalRasH());
|
||||||
RgbaToRgb(finalImage, vecRgb, finalEmber.m_FinalRasW, finalEmber.m_FinalRasH);
|
|
||||||
|
|
||||||
finalImagep = vecRgb.data();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
finalImagep = finalImage.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
finalImagep = finalImage.data();
|
||||||
writeSuccess = false;
|
writeSuccess = false;
|
||||||
|
|
||||||
if (opt.Format() == "png")
|
if (opt.Format() == "png")
|
||||||
|
@ -49,8 +49,8 @@ END
|
|||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 0,4,1,7
|
FILEVERSION 0,4,1,8
|
||||||
PRODUCTVERSION 0,4,1,7
|
PRODUCTVERSION 0,4,1,8
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
@ -67,12 +67,12 @@ BEGIN
|
|||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Open Source"
|
VALUE "CompanyName", "Open Source"
|
||||||
VALUE "FileDescription", "Renders fractal flames as single images"
|
VALUE "FileDescription", "Renders fractal flames as single images"
|
||||||
VALUE "FileVersion", "0.4.1.7"
|
VALUE "FileVersion", "0.4.1.8"
|
||||||
VALUE "InternalName", "EmberRender.rc"
|
VALUE "InternalName", "EmberRender.rc"
|
||||||
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
|
VALUE "LegalCopyright", "Copyright (C) Matt Feemster 2013, GPL v3"
|
||||||
VALUE "OriginalFilename", "EmberRender.rc"
|
VALUE "OriginalFilename", "EmberRender.rc"
|
||||||
VALUE "ProductName", "Ember Render"
|
VALUE "ProductName", "Ember Render"
|
||||||
VALUE "ProductVersion", "0.4.1.7"
|
VALUE "ProductVersion", "0.4.1.8"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p align="center"><br/><span style=" font-size:12pt;">Fractorium 0.4.1.7 Beta</span></p><p align="center"><span style=" font-size:10pt;"><br/>A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.</span></p><p align="center"><span style=" font-size:10pt;">Matt Feemster</span></p></body></html></string>
|
<string><html><head/><body><p align="center"><br/><span style=" font-size:12pt;">Fractorium 0.4.1.8 Beta</span></p><p align="center"><span style=" font-size:10pt;"><br/>A Qt-based fractal flame editor which uses a C++ re-write of the flam3 algorithm named Ember and a GPU capable version named EmberCL which implements a portion of the cuburn algorithm in OpenCL.</span></p><p align="center"><span style=" font-size:10pt;">Matt Feemster</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
|
@ -152,7 +152,8 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
|
|||||||
m_Run = true;
|
m_Run = true;
|
||||||
m_TotalTimer.Tic();//Begin timing for progress of all operations.
|
m_TotalTimer.Tic();//Begin timing for progress of all operations.
|
||||||
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
|
m_GuiState = m_FinalRenderDialog->State();//Cache render settings from the GUI before running.
|
||||||
|
m_FinalImageIndex = 0;
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
|
bool doAll = m_GuiState.m_DoAll && m_EmberFile.Size() > 1;
|
||||||
uint currentStripForProgress = 0;//Sort of a hack to get the strip value to the progress function.
|
uint currentStripForProgress = 0;//Sort of a hack to get the strip value to the progress function.
|
||||||
@ -216,6 +217,7 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
|
|||||||
//even when using double precision, which most cards at the time of this writing already exceed.
|
//even when using double precision, which most cards at the time of this writing already exceed.
|
||||||
m_GuiState.m_Strips = 1;
|
m_GuiState.m_Strips = 1;
|
||||||
m_Renderer->SetEmber(m_EmberFile.m_Embers);//Copy all embers to the local storage inside the renderer.
|
m_Renderer->SetEmber(m_EmberFile.m_Embers);//Copy all embers to the local storage inside the renderer.
|
||||||
|
uint finalImageIndex = m_FinalImageIndex;
|
||||||
|
|
||||||
//Render each image, cancelling if m_Run ever gets set to false.
|
//Render each image, cancelling if m_Run ever gets set to false.
|
||||||
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
|
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
|
||||||
@ -224,35 +226,44 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
|
|||||||
m_Renderer->Reset();//Have to manually set this since the ember is not set each time through.
|
m_Renderer->Reset();//Have to manually set this since the ember is not set each time through.
|
||||||
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
|
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
|
||||||
|
|
||||||
StripsRender<T>(m_Renderer.get(), m_EmberFile.m_Embers[i], m_FinalImage, i, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
|
//Can't use strips render here. Run() must be called directly for animation.
|
||||||
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
|
if (m_Renderer->Run(m_FinalImage[finalImageIndex], i) != RENDER_OK)
|
||||||
[&](size_t strip) { m_Stats = m_Renderer->Stats(); },//Post strip.
|
|
||||||
[&](size_t strip)//Error.
|
|
||||||
{
|
{
|
||||||
Output("Renderering failed.\n");
|
Output("Renderering failed.\n");
|
||||||
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRenderDialog->ui.FinalRenderTextOutput, false);//Internally calls invoke.
|
m_Fractorium->ErrorReportToQTextEdit(m_Renderer->ErrorReport(), m_FinalRenderDialog->ui.FinalRenderTextOutput, false);//Internally calls invoke.
|
||||||
},
|
}
|
||||||
[&](Ember<T>& finalEmber) { RenderComplete(finalEmber); });//Final strip.
|
else
|
||||||
|
{
|
||||||
|
if (m_WriteThread.joinable())
|
||||||
|
m_WriteThread.join();
|
||||||
|
|
||||||
|
SetProgressComplete(100);
|
||||||
|
m_Stats = m_Renderer->Stats();
|
||||||
|
m_FinalImageIndex = finalImageIndex;//Will be used inside of RenderComplete(). Set here when no threads are running.
|
||||||
|
//RenderComplete(m_EmberFile.m_Embers[i]);//Non-threaded version for testing.
|
||||||
|
m_WriteThread = std::thread([&] { RenderComplete(m_EmberFile.m_Embers[i]); });
|
||||||
|
}
|
||||||
|
|
||||||
|
finalImageIndex ^= 1;//Toggle the index.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_WriteThread.joinable())
|
||||||
|
m_WriteThread.join();
|
||||||
}
|
}
|
||||||
else//Render all images, but not as an animation sequence (without temporal samples motion blur).
|
else//Render all images, but not as an animation sequence (without temporal samples motion blur).
|
||||||
{
|
{
|
||||||
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
|
|
||||||
{
|
|
||||||
m_EmberFile.m_Embers[i].m_TemporalSamples = 1;//No temporal sampling.
|
|
||||||
}
|
|
||||||
|
|
||||||
//Render each image, cancelling if m_Run ever gets set to false.
|
//Render each image, cancelling if m_Run ever gets set to false.
|
||||||
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
|
for (i = 0; i < m_EmberFile.Size() && m_Run; i++)
|
||||||
{
|
{
|
||||||
Output("Image " + ToString(m_FinishedImageCount) + ":\n" + ComposePath(QString::fromStdString(m_EmberFile.m_Embers[i].m_Name)));
|
Output("Image " + ToString(m_FinishedImageCount) + ":\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]);
|
m_Renderer->SetEmber(m_EmberFile.m_Embers[i]);
|
||||||
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_Renderer->PrepFinalAccumVector(m_FinalImage[m_FinalImageIndex]);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run().
|
||||||
m_Stats.Clear();
|
m_Stats.Clear();
|
||||||
Memset(m_FinalImage);
|
Memset(m_FinalImage[m_FinalImageIndex]);
|
||||||
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
|
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(), m_EmberFile.m_Embers[i], m_FinalImage[m_FinalImageIndex], 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
|
||||||
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
|
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
|
||||||
[&](size_t strip) { m_Stats += m_Renderer->Stats(); },//Post strip.
|
[&](size_t strip) { m_Stats += m_Renderer->Stats(); },//Post strip.
|
||||||
[&](size_t strip)//Error.
|
[&](size_t strip)//Error.
|
||||||
@ -270,13 +281,13 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
|
|||||||
ResetProgress();
|
ResetProgress();
|
||||||
m_Ember->m_TemporalSamples = 1;
|
m_Ember->m_TemporalSamples = 1;
|
||||||
m_Renderer->SetEmber(*m_Ember);
|
m_Renderer->SetEmber(*m_Ember);
|
||||||
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_Renderer->PrepFinalAccumVector(m_FinalImage[m_FinalImageIndex]);//Must manually call this first because it could be erroneously made smaller due to strips if called inside Renderer::Run().
|
||||||
m_Stats.Clear();
|
m_Stats.Clear();
|
||||||
Memset(m_FinalImage);
|
Memset(m_FinalImage[m_FinalImageIndex]);
|
||||||
Output(ComposePath(QString::fromStdString(m_Ember->m_Name)));
|
Output(ComposePath(QString::fromStdString(m_Ember->m_Name)));
|
||||||
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
|
m_RenderTimer.Tic();//Toc() is called in RenderComplete().
|
||||||
|
|
||||||
StripsRender<T>(m_Renderer.get(), *m_Ember, m_FinalImage, 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
|
StripsRender<T>(m_Renderer.get(), *m_Ember, m_FinalImage[m_FinalImageIndex], 0, m_GuiState.m_Strips, m_GuiState.m_YAxisUp,
|
||||||
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
|
[&](size_t strip) { currentStripForProgress = strip; },//Pre strip.
|
||||||
[&](size_t strip) { m_Stats += m_Renderer->Stats(); },//Post strip.
|
[&](size_t strip) { m_Stats += m_Renderer->Stats(); },//Post strip.
|
||||||
[&](size_t strip)//Error.
|
[&](size_t strip)//Error.
|
||||||
@ -287,6 +298,7 @@ FinalRenderEmberController<T>::FinalRenderEmberController(FractoriumFinalRenderD
|
|||||||
[&](Ember<T>& finalEmber) { RenderComplete(finalEmber); });//Final strip.
|
[&](Ember<T>& finalEmber) { RenderComplete(finalEmber); });//Final strip.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_FinalImageIndex = 0;
|
||||||
QString totalTimeString = "All renders completed in: " + QString::fromStdString(m_TotalTimer.Format(m_TotalTimer.Toc())) + ".";
|
QString totalTimeString = "All renders completed in: " + QString::fromStdString(m_TotalTimer.Format(m_TotalTimer.Toc())) + ".";
|
||||||
Output(totalTimeString);
|
Output(totalTimeString);
|
||||||
|
|
||||||
@ -589,7 +601,7 @@ tuple<size_t, size_t, size_t> FinalRenderEmberController<T>::SyncAndComputeMemor
|
|||||||
CancelPreviewRender();
|
CancelPreviewRender();
|
||||||
m_FinalPreviewRenderFunc();
|
m_FinalPreviewRenderFunc();
|
||||||
|
|
||||||
p = m_Renderer->MemoryRequired(strips, true);
|
p = m_Renderer->MemoryRequired(strips, true, m_FinalRenderDialog->DoSequence());
|
||||||
iterCount = m_Renderer->TotalIterCount(strips);
|
iterCount = m_Renderer->TotalIterCount(strips);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,11 +689,15 @@ void FinalRenderEmberController<T>::RenderComplete(Ember<T>& ember)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_FinishedImageCount++;
|
m_FinishedImageCount++;
|
||||||
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));//Just to be safe.
|
|
||||||
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));
|
//In a thread if animating, so don't set to complete because it'll be out of sync with the rest of the progress bars.
|
||||||
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, 100));
|
if (!m_GuiState.m_DoSequence)
|
||||||
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, int((float(m_FinishedImageCount) / float(m_ImageCount)) * 100)));
|
{
|
||||||
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(const QString&, ToString(m_FinishedImageCount) + " / " + ToString(m_ImageCount)));
|
SetProgressComplete(100);//Just to be safe.
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderTotalProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, int((float(m_FinishedImageCount) / float(m_ImageCount)) * 100)));
|
||||||
|
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderImageCountLabel, "setText", Qt::QueuedConnection, Q_ARG(const QString&, ToString(m_FinishedImageCount) + " / " + ToString(m_ImageCount)));
|
||||||
|
|
||||||
status = "Pure render time: " + QString::fromStdString(renderTimeString);
|
status = "Pure render time: " + QString::fromStdString(renderTimeString);
|
||||||
Output(status);
|
Output(status);
|
||||||
@ -733,6 +749,19 @@ void FinalRenderEmberController<T>::SyncGuiToEmber(Ember<T>& ember, size_t width
|
|||||||
ember.m_Supersample = m_FinalRenderDialog->m_SupersampleSpin->value();
|
ember.m_Supersample = m_FinalRenderDialog->m_SupersampleSpin->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the iteration, density filter, and final accumulation progress bars to the same value.
|
||||||
|
/// Usually 0 or 100.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="val">The value to set them to</param>
|
||||||
|
template <typename T>
|
||||||
|
void FinalRenderEmberController<T>::SetProgressComplete(int val)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderIterationProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, val));//Just to be safe.
|
||||||
|
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderFilteringProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, val));
|
||||||
|
QMetaObject::invokeMethod(m_FinalRenderDialog->ui.FinalRenderAccumProgress, "setValue", Qt::QueuedConnection, Q_ARG(int, val));
|
||||||
|
}
|
||||||
|
|
||||||
template class FinalRenderEmberController<float>;
|
template class FinalRenderEmberController<float>;
|
||||||
|
|
||||||
#ifdef DO_DOUBLE
|
#ifdef DO_DOUBLE
|
||||||
|
@ -131,6 +131,7 @@ protected:
|
|||||||
void CancelPreviewRender();
|
void CancelPreviewRender();
|
||||||
void RenderComplete(Ember<T>& ember);
|
void RenderComplete(Ember<T>& ember);
|
||||||
void SyncGuiToEmber(Ember<T>& ember, size_t widthOverride = 0, size_t heightOverride = 0);
|
void SyncGuiToEmber(Ember<T>& ember, size_t widthOverride = 0, size_t heightOverride = 0);
|
||||||
|
void SetProgressComplete(int val);
|
||||||
|
|
||||||
Ember<T>* m_Ember;
|
Ember<T>* m_Ember;
|
||||||
Ember<T> m_PreviewEmber;
|
Ember<T> m_PreviewEmber;
|
||||||
|
Binary file not shown.
@ -23,6 +23,7 @@ FractoriumEmberControllerBase::FractoriumEmberControllerBase(Fractorium* fractor
|
|||||||
m_RenderType = CPU_RENDERER;
|
m_RenderType = CPU_RENDERER;
|
||||||
m_OutputTexID = 0;
|
m_OutputTexID = 0;
|
||||||
m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
|
m_SubBatchCount = 1;//Will be ovewritten by the options on first render.
|
||||||
|
m_FinalImageIndex = 0;
|
||||||
m_Fractorium = fractorium;
|
m_Fractorium = fractorium;
|
||||||
m_RenderTimer = nullptr;
|
m_RenderTimer = nullptr;
|
||||||
m_RenderRestartTimer = nullptr;
|
m_RenderRestartTimer = nullptr;
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
|
|
||||||
//Embers.
|
//Embers.
|
||||||
virtual void SetEmber(const Ember<float>& ember, bool verbatim = false) { }
|
virtual void SetEmber(const Ember<float>& ember, bool verbatim = false) { }
|
||||||
virtual void CopyEmber(Ember<float>& ember, std::function<void(Ember<float>& ember)> perEmberOperation/* = [&](Ember<float>& ember) { }*/) { }
|
virtual void CopyEmber(Ember<float>& ember, std::function<void(Ember<float>& ember)> perEmberOperation/* = [&](Ember<float>& ember) { }*/) { }//Uncomment default lambdas once LLVM fixes a crash in their compiler with default lambda parameters.//TODO
|
||||||
virtual void SetEmberFile(const EmberFile<float>& emberFile) { }
|
virtual void SetEmberFile(const EmberFile<float>& emberFile) { }
|
||||||
virtual void CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation/* = [&](Ember<float>& ember) { }*/) { }
|
virtual void CopyEmberFile(EmberFile<float>& emberFile, std::function<void(Ember<float>& ember)> perEmberOperation/* = [&](Ember<float>& ember) { }*/) { }
|
||||||
virtual void SetTempPalette(const Palette<float>& palette) { }
|
virtual void SetTempPalette(const Palette<float>& palette) { }
|
||||||
@ -202,7 +202,7 @@ public:
|
|||||||
void DeleteRenderer();
|
void DeleteRenderer();
|
||||||
void SaveCurrentRender(const QString& filename, bool forcePull);
|
void SaveCurrentRender(const QString& filename, bool forcePull);
|
||||||
RendererBase* Renderer() { return m_Renderer.get(); }
|
RendererBase* Renderer() { return m_Renderer.get(); }
|
||||||
vector<byte>* FinalImage() { return &m_FinalImage; }
|
vector<byte>* FinalImage() { return &(m_FinalImage[m_FinalImageIndex]); }
|
||||||
vector<byte>* PreviewFinalImage() { return &m_PreviewFinalImage; }
|
vector<byte>* PreviewFinalImage() { return &m_PreviewFinalImage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -215,6 +215,7 @@ protected:
|
|||||||
bool m_Rendering;
|
bool m_Rendering;
|
||||||
bool m_Shared;
|
bool m_Shared;
|
||||||
bool m_LastEditWasUndoRedo;
|
bool m_LastEditWasUndoRedo;
|
||||||
|
uint m_FinalImageIndex;
|
||||||
uint m_Platform;
|
uint m_Platform;
|
||||||
uint m_Device;
|
uint m_Device;
|
||||||
uint m_SubBatchCount;
|
uint m_SubBatchCount;
|
||||||
@ -229,7 +230,8 @@ protected:
|
|||||||
QString m_LastSaveAll;
|
QString m_LastSaveAll;
|
||||||
QString m_LastSaveCurrent;
|
QString m_LastSaveCurrent;
|
||||||
CriticalSection m_Cs;
|
CriticalSection m_Cs;
|
||||||
vector<byte> m_FinalImage;
|
std::thread m_WriteThread;
|
||||||
|
vector<byte> m_FinalImage[2];
|
||||||
vector<byte> m_PreviewFinalImage;
|
vector<byte> m_PreviewFinalImage;
|
||||||
vector<eProcessAction> m_ProcessActions;
|
vector<eProcessAction> m_ProcessActions;
|
||||||
unique_ptr<EmberNs::RendererBase> m_Renderer;
|
unique_ptr<EmberNs::RendererBase> m_Renderer;
|
||||||
|
@ -124,9 +124,9 @@ void FractoriumEmberControllerBase::SaveCurrentRender(const QString& filename, b
|
|||||||
FractoriumSettings* settings = m_Fractorium->m_Settings;
|
FractoriumSettings* settings = m_Fractorium->m_Settings;
|
||||||
RendererCLBase* rendererCL = dynamic_cast<RendererCLBase*>(m_Renderer.get());
|
RendererCLBase* rendererCL = dynamic_cast<RendererCLBase*>(m_Renderer.get());
|
||||||
|
|
||||||
if (forcePull && rendererCL && m_Renderer->PrepFinalAccumVector(m_FinalImage))
|
if (forcePull && rendererCL && m_Renderer->PrepFinalAccumVector(m_FinalImage[m_FinalImageIndex]))
|
||||||
{
|
{
|
||||||
if (!rendererCL->ReadFinal(m_FinalImage.data()))
|
if (!rendererCL->ReadFinal(m_FinalImage[m_FinalImageIndex].data()))
|
||||||
{
|
{
|
||||||
m_Fractorium->ShowCritical("GPU Read Error", "Could not read image from the GPU, aborting image save.", true);
|
m_Fractorium->ShowCritical("GPU Read Error", "Could not read image from the GPU, aborting image save.", true);
|
||||||
return;
|
return;
|
||||||
@ -134,17 +134,17 @@ void FractoriumEmberControllerBase::SaveCurrentRender(const QString& filename, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Ensure dimensions are valid.
|
//Ensure dimensions are valid.
|
||||||
if (m_FinalImage.size() < (width * height * m_Renderer->NumChannels() * m_Renderer->BytesPerChannel()))
|
if (m_FinalImage[m_FinalImageIndex].size() < (width * height * m_Renderer->NumChannels() * m_Renderer->BytesPerChannel()))
|
||||||
{
|
{
|
||||||
m_Fractorium->ShowCritical("Save Failed", "Dimensions didn't match, not saving.", true);
|
m_Fractorium->ShowCritical("Save Failed", "Dimensions didn't match, not saving.", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = m_FinalImage.data();//Png and channels == 4.
|
data = m_FinalImage[m_FinalImageIndex].data();//Png and channels == 4.
|
||||||
|
|
||||||
if ((suffix == "jpg" || suffix == "bmp") && m_Renderer->NumChannels() == 4)
|
if ((suffix == "jpg" || suffix == "bmp") && m_Renderer->NumChannels() == 4)
|
||||||
{
|
{
|
||||||
RgbaToRgb(m_FinalImage, vecRgb, width, height);
|
RgbaToRgb(m_FinalImage[m_FinalImageIndex], vecRgb, width, height);
|
||||||
|
|
||||||
data = vecRgb.data();
|
data = vecRgb.data();
|
||||||
}
|
}
|
||||||
@ -358,7 +358,7 @@ bool FractoriumEmberController<T>::Render()
|
|||||||
if (ProcessState() != ACCUM_DONE)
|
if (ProcessState() != ACCUM_DONE)
|
||||||
{
|
{
|
||||||
//if (m_Renderer->Run(m_FinalImage, 0) == RENDER_OK)//Full, non-incremental render for debugging.
|
//if (m_Renderer->Run(m_FinalImage, 0) == RENDER_OK)//Full, non-incremental render for debugging.
|
||||||
if (m_Renderer->Run(m_FinalImage, 0, m_SubBatchCount, iterBegin) == RENDER_OK)//Force output on iterBegin.
|
if (m_Renderer->Run(m_FinalImage[m_FinalImageIndex], 0, m_SubBatchCount, iterBegin) == RENDER_OK)//Force output on iterBegin.
|
||||||
{
|
{
|
||||||
//The amount to increment sub batch while rendering proceeds is purely empirical.
|
//The amount to increment sub batch while rendering proceeds is purely empirical.
|
||||||
//Change later if better values can be derived/observed.
|
//Change later if better values can be derived/observed.
|
||||||
@ -433,7 +433,7 @@ bool FractoriumEmberController<T>::Render()
|
|||||||
//Update it on finish because the rendering process is completely done.
|
//Update it on finish because the rendering process is completely done.
|
||||||
if (iterBegin || ProcessState() == ACCUM_DONE)
|
if (iterBegin || ProcessState() == ACCUM_DONE)
|
||||||
{
|
{
|
||||||
if (m_FinalImage.size() == m_Renderer->FinalBufferSize())//Make absolutely sure the correct amount of data is passed.
|
if (m_FinalImage[m_FinalImageIndex].size() == m_Renderer->FinalBufferSize())//Make absolutely sure the correct amount of data is passed.
|
||||||
//gl->repaint();
|
//gl->repaint();
|
||||||
gl->update();
|
gl->update();
|
||||||
|
|
||||||
@ -460,7 +460,7 @@ bool FractoriumEmberController<T>::Render()
|
|||||||
m_Rendering = false;
|
m_Rendering = false;
|
||||||
StopRenderTimer(true);
|
StopRenderTimer(true);
|
||||||
m_Fractorium->m_RenderStatusLabel->setText("Rendering failed 3 or more times, stopping all rendering, see info tab. Try changing renderer types.");
|
m_Fractorium->m_RenderStatusLabel->setText("Rendering failed 3 or more times, stopping all rendering, see info tab. Try changing renderer types.");
|
||||||
Memset(m_FinalImage);
|
Memset(m_FinalImage[m_FinalImageIndex]);
|
||||||
|
|
||||||
if (rendererCL)
|
if (rendererCL)
|
||||||
rendererCL->ClearFinal();
|
rendererCL->ClearFinal();
|
||||||
@ -642,6 +642,11 @@ bool Fractorium::CreateControllerFromOptions()
|
|||||||
if (m_Controller.get())
|
if (m_Controller.get())
|
||||||
{
|
{
|
||||||
m_Controller->CopyTempPalette(tempPalette);//Convert float to double or save double verbatim;
|
m_Controller->CopyTempPalette(tempPalette);//Convert float to double or save double verbatim;
|
||||||
|
|
||||||
|
//Replace below with this once LLVM fixes a crash in their compiler with default lambda parameters.//TODO
|
||||||
|
//m_Controller->CopyEmber(ed);
|
||||||
|
//m_Controller->CopyEmberFile(efd);
|
||||||
|
|
||||||
#ifdef DO_DOUBLE
|
#ifdef DO_DOUBLE
|
||||||
m_Controller->CopyEmber(ed, [&](Ember<double>& ember) { });
|
m_Controller->CopyEmber(ed, [&](Ember<double>& ember) { });
|
||||||
m_Controller->CopyEmberFile(efd, [&](Ember<double>& ember) { });
|
m_Controller->CopyEmberFile(efd, [&](Ember<double>& ember) { });
|
||||||
|
Loading…
Reference in New Issue
Block a user