diff --git a/.gitignore b/.gitignore
index 9de495d..d9e25a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -257,6 +257,5 @@ Builds/include/GL
/.vs/slnx.sqlite
/Deps/Include/OpenEXR
/main.pro.user.294b646
-/Builds/MSVC/VS2019/.vs/Fractorium
-/Builds/MSVC/VS2017/.vs/config
/Deps/Include/Imath
+/Builds/MSVC/Solution/.vs/Fractorium
diff --git a/Builds/MSVC/VS2019/Ember.rc b/Builds/MSVC/Solution/Ember.rc
similarity index 100%
rename from Builds/MSVC/VS2019/Ember.rc
rename to Builds/MSVC/Solution/Ember.rc
diff --git a/Builds/MSVC/VS2019/Ember.vcxproj b/Builds/MSVC/Solution/Ember.vcxproj
similarity index 99%
rename from Builds/MSVC/VS2019/Ember.vcxproj
rename to Builds/MSVC/Solution/Ember.vcxproj
index 741f855..ae52422 100644
--- a/Builds/MSVC/VS2019/Ember.vcxproj
+++ b/Builds/MSVC/Solution/Ember.vcxproj
@@ -23,14 +23,14 @@
true
MultiByte
false
- v142
+ v143
DynamicLibrary
false
false
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/Ember.vcxproj.filters b/Builds/MSVC/Solution/Ember.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/Ember.vcxproj.filters
rename to Builds/MSVC/Solution/Ember.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/EmberAnimate.rc b/Builds/MSVC/Solution/EmberAnimate.rc
similarity index 100%
rename from Builds/MSVC/VS2019/EmberAnimate.rc
rename to Builds/MSVC/Solution/EmberAnimate.rc
diff --git a/Builds/MSVC/VS2019/EmberAnimate.vcxproj b/Builds/MSVC/Solution/EmberAnimate.vcxproj
similarity index 99%
rename from Builds/MSVC/VS2019/EmberAnimate.vcxproj
rename to Builds/MSVC/Solution/EmberAnimate.vcxproj
index 5d17978..e09a0f6 100644
--- a/Builds/MSVC/VS2019/EmberAnimate.vcxproj
+++ b/Builds/MSVC/Solution/EmberAnimate.vcxproj
@@ -23,14 +23,14 @@
true
MultiByte
false
- v142
+ v143
Application
false
false
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/EmberAnimate.vcxproj.filters b/Builds/MSVC/Solution/EmberAnimate.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/EmberAnimate.vcxproj.filters
rename to Builds/MSVC/Solution/EmberAnimate.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/EmberCL.rc b/Builds/MSVC/Solution/EmberCL.rc
similarity index 100%
rename from Builds/MSVC/VS2019/EmberCL.rc
rename to Builds/MSVC/Solution/EmberCL.rc
diff --git a/Builds/MSVC/VS2019/EmberCL.vcxproj b/Builds/MSVC/Solution/EmberCL.vcxproj
similarity index 99%
rename from Builds/MSVC/VS2019/EmberCL.vcxproj
rename to Builds/MSVC/Solution/EmberCL.vcxproj
index e4f34d2..7b602ec 100644
--- a/Builds/MSVC/VS2019/EmberCL.vcxproj
+++ b/Builds/MSVC/Solution/EmberCL.vcxproj
@@ -23,14 +23,14 @@
true
MultiByte
false
- v142
+ v143
DynamicLibrary
false
false
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/EmberCL.vcxproj.filters b/Builds/MSVC/Solution/EmberCL.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/EmberCL.vcxproj.filters
rename to Builds/MSVC/Solution/EmberCL.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/EmberGenome.rc b/Builds/MSVC/Solution/EmberGenome.rc
similarity index 100%
rename from Builds/MSVC/VS2019/EmberGenome.rc
rename to Builds/MSVC/Solution/EmberGenome.rc
diff --git a/Builds/MSVC/VS2019/EmberGenome.vcxproj b/Builds/MSVC/Solution/EmberGenome.vcxproj
similarity index 99%
rename from Builds/MSVC/VS2019/EmberGenome.vcxproj
rename to Builds/MSVC/Solution/EmberGenome.vcxproj
index 6a4ec27..6d2f5ca 100644
--- a/Builds/MSVC/VS2019/EmberGenome.vcxproj
+++ b/Builds/MSVC/Solution/EmberGenome.vcxproj
@@ -23,14 +23,14 @@
true
MultiByte
false
- v142
+ v143
Application
false
false
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/EmberGenome.vcxproj.filters b/Builds/MSVC/Solution/EmberGenome.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/EmberGenome.vcxproj.filters
rename to Builds/MSVC/Solution/EmberGenome.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/EmberRender.rc b/Builds/MSVC/Solution/EmberRender.rc
similarity index 100%
rename from Builds/MSVC/VS2019/EmberRender.rc
rename to Builds/MSVC/Solution/EmberRender.rc
diff --git a/Builds/MSVC/VS2019/EmberRender.vcxproj b/Builds/MSVC/Solution/EmberRender.vcxproj
similarity index 99%
rename from Builds/MSVC/VS2019/EmberRender.vcxproj
rename to Builds/MSVC/Solution/EmberRender.vcxproj
index b3785aa..e64fe7f 100644
--- a/Builds/MSVC/VS2019/EmberRender.vcxproj
+++ b/Builds/MSVC/Solution/EmberRender.vcxproj
@@ -23,14 +23,14 @@
true
MultiByte
false
- v142
+ v143
Application
false
false
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/EmberRender.vcxproj.filters b/Builds/MSVC/Solution/EmberRender.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/EmberRender.vcxproj.filters
rename to Builds/MSVC/Solution/EmberRender.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/EmberTester.vcxproj b/Builds/MSVC/Solution/EmberTester.vcxproj
similarity index 98%
rename from Builds/MSVC/VS2019/EmberTester.vcxproj
rename to Builds/MSVC/Solution/EmberTester.vcxproj
index 4e74a8c..a660a10 100644
--- a/Builds/MSVC/VS2019/EmberTester.vcxproj
+++ b/Builds/MSVC/Solution/EmberTester.vcxproj
@@ -23,14 +23,14 @@
true
MultiByte
false
- v142
+ v143
Application
false
false
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/EmberTester.vcxproj.filters b/Builds/MSVC/Solution/EmberTester.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/EmberTester.vcxproj.filters
rename to Builds/MSVC/Solution/EmberTester.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/Fractorium.rc b/Builds/MSVC/Solution/Fractorium.rc
similarity index 100%
rename from Builds/MSVC/VS2019/Fractorium.rc
rename to Builds/MSVC/Solution/Fractorium.rc
diff --git a/Builds/MSVC/VS2019/Fractorium.sln b/Builds/MSVC/Solution/Fractorium.sln
similarity index 100%
rename from Builds/MSVC/VS2019/Fractorium.sln
rename to Builds/MSVC/Solution/Fractorium.sln
diff --git a/Builds/MSVC/VS2019/Fractorium.vcxproj b/Builds/MSVC/Solution/Fractorium.vcxproj
similarity index 99%
rename from Builds/MSVC/VS2019/Fractorium.vcxproj
rename to Builds/MSVC/Solution/Fractorium.vcxproj
index f9b6906..1ce0084 100644
--- a/Builds/MSVC/VS2019/Fractorium.vcxproj
+++ b/Builds/MSVC/Solution/Fractorium.vcxproj
@@ -19,12 +19,12 @@
Application
MultiByte
- v142
+ v143
Application
MultiByte
- v142
+ v143
diff --git a/Builds/MSVC/VS2019/Fractorium.vcxproj.filters b/Builds/MSVC/Solution/Fractorium.vcxproj.filters
similarity index 100%
rename from Builds/MSVC/VS2019/Fractorium.vcxproj.filters
rename to Builds/MSVC/Solution/Fractorium.vcxproj.filters
diff --git a/Builds/MSVC/VS2019/flam3-palettes.xml b/Builds/MSVC/Solution/flam3-palettes.xml
similarity index 100%
rename from Builds/MSVC/VS2019/flam3-palettes.xml
rename to Builds/MSVC/Solution/flam3-palettes.xml
diff --git a/Builds/MSVC/VS2019/resource.h b/Builds/MSVC/Solution/resource.h
similarity index 100%
rename from Builds/MSVC/VS2019/resource.h
rename to Builds/MSVC/Solution/resource.h
diff --git a/Builds/MSVC/VS2019/resource1.h b/Builds/MSVC/Solution/resource1.h
similarity index 100%
rename from Builds/MSVC/VS2019/resource1.h
rename to Builds/MSVC/Solution/resource1.h
diff --git a/Builds/MSVC/VS2019/zlib.props b/Builds/MSVC/Solution/zlib.props
similarity index 100%
rename from Builds/MSVC/VS2019/zlib.props
rename to Builds/MSVC/Solution/zlib.props
diff --git a/Source/EmberAnimate/EmberAnimate.cpp b/Source/EmberAnimate/EmberAnimate.cpp
index efdd24b..32b0118 100644
--- a/Source/EmberAnimate/EmberAnimate.cpp
+++ b/Source/EmberAnimate/EmberAnimate.cpp
@@ -336,6 +336,14 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
r->Priority(eThreadPriority(Clamp(intmax_t(opt.Priority()), intmax_t(eThreadPriority::LOWEST), intmax_t(eThreadPriority::HIGHEST))));
}
+ const auto doBmp = Find(opt.Format(), "bmp");
+ const auto doJpg = Find(opt.Format(), "jpg");
+ const auto doExr16 = Find(opt.Format(), "exr");
+ const auto doExr32 = Find(opt.Format(), "exr32");
+ const auto doPng8 = Find(opt.Format(), "png");
+ const auto doPng16 = Find(opt.Format(), "png16");
+ const auto doOnlyPng8 = doPng8 && !doPng16;
+ const auto doOnlyExr16 = doExr16 && !doExr32;
std::function&, string, EmberImageComments, size_t, size_t, size_t)> saveFunc = [&](vector& finalImage,
string baseFilename,//These are copies because this will be launched in a thread.
EmberImageComments comments,
@@ -345,14 +353,6 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
{
const auto finalImagep = finalImage.data();
const auto size = w * h;
- const auto doBmp = Find(opt.Format(), "bmp");
- const auto doJpg = Find(opt.Format(), "jpg");
- const auto doExr16 = Find(opt.Format(), "exr");
- const auto doExr32 = Find(opt.Format(), "exr32");
- const auto doPng8 = Find(opt.Format(), "png");
- const auto doPng16 = Find(opt.Format(), "png16");
- const auto doOnlyPng8 = doPng8 && !doPng16;
- const auto doOnlyExr16 = doExr16 && !doExr32;
vector rgb8Image;
vector writeFileThreads;
writeFileThreads.reserve(6);
@@ -514,6 +514,84 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
while ((ftime = (atomfTime.fetch_add(opt.Dtime()) + opt.Dtime())) <= opt.LastFrame())
{
const auto localTime = static_cast(ftime) - opt.Dtime();
+ const auto baseFilename = MakeAnimFilename(inputPath, opt.Prefix(), opt.Suffix(), "", padding, size_t(localTime));
+
+ if (opt.IgnoreExisting())
+ {
+ auto doRender = false;
+
+ if (doBmp)
+ {
+ const auto fn = baseFilename + ".bmp";
+
+ if (!FileExists(fn))
+ doRender = true;
+ }
+
+ if (!doRender && doJpg)
+ {
+ const auto fn = baseFilename + ".jpg";
+
+ if (!FileExists(fn))
+ doRender = true;
+ }
+
+ if (!doRender && doPng8)
+ {
+ bool doBothPng = doPng16 && (opt.Format().find("png") != opt.Format().rfind("png"));
+
+ if (doBothPng || doOnlyPng8)//8-bit PNG.
+ {
+ const auto fn = baseFilename + ".png";
+
+ if (!FileExists(fn))
+ doRender = true;
+ }
+
+ if (!doRender && doPng16)//16-bit PNG.
+ {
+ auto fn = baseFilename;
+
+ if (doBothPng)//Add suffix if they specified both PNG.
+ fn += "_p16";
+
+ fn += ".png";
+
+ if (!FileExists(fn))
+ doRender = true;
+ }
+ }
+
+ if (!doRender && doExr16)
+ {
+ bool doBothExr = doExr32 && (opt.Format().find("exr") != opt.Format().rfind("exr"));
+
+ if (doBothExr || doOnlyExr16)//16-bit EXR
+ {
+ const auto fn = baseFilename + ".exr";
+
+ if (!FileExists(fn))
+ doRender = true;
+ }
+
+ if (!doRender && doExr32)//32-bit EXR.
+ {
+ auto fn = baseFilename;
+
+ if (doBothExr)//Add suffix if they specified both EXR.
+ fn += "_exr32";
+
+ fn += ".exr"; if (!FileExists(fn))
+ doRender = true;
+ }
+ }
+
+ if (!doRender)
+ {
+ VerbosePrint("Skipping " + baseFilename + " because --ignore-existing was specified and all of the files with the requested extensions already exist.");
+ continue;
+ }
+ }
if (opt.Verbose() && ((opt.LastFrame() - opt.FirstFrame()) / opt.Dtime() >= 1))
{
@@ -568,7 +646,6 @@ bool EmberAnimate(int argc, _TCHAR* argv[], EmberOptions& opt)
//when running with OpenCL. Call join() to ensure the previous thread call has completed.
Join(writeThread);
const auto threadVecIndex = finalImageIndex;//Cache before launching thread.
- const auto baseFilename = MakeAnimFilename(inputPath, opt.Prefix(), opt.Suffix(), "", padding, size_t(localTime));
if (opt.ThreadedWrite())//Copies of all but the first parameter are passed to saveFunc(), to avoid conflicting with those values changing when starting the render for the next image.
{
diff --git a/Source/EmberCommon/EmberCommon.h b/Source/EmberCommon/EmberCommon.h
index 21a4a2b..90d8735 100644
--- a/Source/EmberCommon/EmberCommon.h
+++ b/Source/EmberCommon/EmberCommon.h
@@ -864,7 +864,7 @@ static vector*> FindVarsWithWithout(const vector
-/// The vector of variation pointers to search
+/// The vector of variation pointers to search
/// The vector of strings to search for
/// True to find all variations which don't match any strings, false to break after the first non-match is found.
/// A vector of pointers to variations whose OpenCL string did not match any string in stringVec
@@ -887,6 +887,32 @@ static vector*> FindVarsWithout(const vector
+/// Check whether a file exists, and optionally if it's not empty.
+///
+/// The full path and file name to check for
+/// Whether to only return true if the file is found and is not empty. Default: true.
+/// True if the file was found and optionally not empty, else false.
+static bool FileExists(const string& filename, bool notempty = true)
+{
+ try
+ {
+ ifstream ifs;
+ ifs.exceptions(ifstream::failbit);
+ ifs.open(filename, ios::binary | ios::ate);
+
+ if (notempty)
+ return ifs.tellg() > 0;//Ensure it exists and wasn't empty.
+ else
+ return true;
+ }
+ catch (...)
+ {
+ }
+
+ return false;
+}
}
///
diff --git a/Source/EmberCommon/EmberOptions.h b/Source/EmberCommon/EmberOptions.h
index d0bbb2c..67cccbc 100644
--- a/Source/EmberCommon/EmberOptions.h
+++ b/Source/EmberCommon/EmberOptions.h
@@ -69,6 +69,7 @@ enum class eOptionIDs : et
OPT_LOCK_ACCUM,
OPT_DUMP_KERNEL,
OPT_FLAM3_COMPAT,
+ OPT_IGNORE_EXISTING,
//Value args.
OPT_NTHREADS,//Int value args.
@@ -376,6 +377,7 @@ public:
INITBOOLOPTION(LockAccum, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_LOCK_ACCUM, _T("--lock_accum"), false, SO_NONE, " --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(DumpKernel, Eob(eOptionUse::OPT_USE_RENDER, eOptionIDs::OPT_DUMP_KERNEL, _T("--dump_kernel"), false, SO_NONE, " --dump_kernel Print the iteration kernel string when using OpenCL (ignored for CPU) [default: false].\n"));
INITBOOLOPTION(Flam3Compat, Eob(eOptionUse::OPT_USE_ALL, eOptionIDs::OPT_FLAM3_COMPAT, _T("--flam3_compat"), false, SO_NONE, " --flam3_compat The behavior of the cos, cosh, cot, coth, csc, csch, sec, sech, sin, sinh, tan and tanh variations are different in flam3/Apophysis versus Chaotica. True for flam3/Apophysis behavior, false for Chaotica behavior [default: true].\n"));
+ INITBOOLOPTION(IgnoreExisting, Eob(eOptionUse::OPT_USE_ANIMATE, eOptionIDs::OPT_IGNORE_EXISTING, _T("--ignore-existing"), false, SO_NONE, " --ignore-existing Skip animating a frame if the output images for all of the specified file output types already exist in the output folder [default: false].\n"));
//Int.
INITINTOPTION(Symmetry, Eoi(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_SYMMETRY, _T("--symmetry"), 0, SO_REQ_SEP, " --symmetry= Set symmetry of result [default: 0].\n"));
INITINTOPTION(SheepGen, Eoi(eOptionUse::OPT_USE_GENOME, eOptionIDs::OPT_SHEEP_GEN, _T("--sheep_gen"), -1, SO_REQ_SEP, " --sheep_gen= Sheep generation of this flame [default: -1].\n"));
@@ -538,6 +540,7 @@ public:
PARSEBOOLOPTION(eOptionIDs::OPT_LOCK_ACCUM, LockAccum);
PARSEBOOLOPTION(eOptionIDs::OPT_DUMP_KERNEL, DumpKernel);
PARSEBOOLOPTION(eOptionIDs::OPT_FLAM3_COMPAT, Flam3Compat);
+ PARSEBOOLOPTION(eOptionIDs::OPT_IGNORE_EXISTING, IgnoreExisting);
PARSEOPTION(eOptionIDs::OPT_SYMMETRY, Symmetry);//Int args
PARSEOPTION(eOptionIDs::OPT_SHEEP_GEN, SheepGen);
PARSEOPTION(eOptionIDs::OPT_SHEEP_ID, SheepId);
@@ -829,6 +832,7 @@ public:
Eob LockAccum;
Eob DumpKernel;
Eob Flam3Compat;
+ Eob IgnoreExisting;
Eoi Symmetry;//Value int.
Eoi SheepGen;