2014-07-08 03:11:14 -04:00
|
|
|
#include "EmberCommonPch.h"
|
|
|
|
#include "EmberGenome.h"
|
|
|
|
#include "JpegUtils.h"
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Set various default test values on the passed in ember.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="ember">The ember to test</param>
|
|
|
|
template <typename T>
|
|
|
|
void SetDefaultTestValues(Ember<T>& ember)
|
|
|
|
{
|
|
|
|
ember.m_Time = 0.0;
|
|
|
|
ember.m_Interp = EMBER_INTERP_LINEAR;
|
|
|
|
ember.m_PaletteInterp = INTERP_HSV;
|
|
|
|
ember.m_Background[0] = 0;
|
|
|
|
ember.m_Background[1] = 0;
|
|
|
|
ember.m_Background[2] = 0;
|
|
|
|
ember.m_Background[3] = 255;
|
|
|
|
ember.m_CenterX = 0;
|
|
|
|
ember.m_CenterY = 0;
|
|
|
|
ember.m_Rotate = 0;
|
|
|
|
ember.m_PixelsPerUnit = 64;
|
|
|
|
ember.m_FinalRasW = 128;
|
|
|
|
ember.m_FinalRasH = 128;
|
|
|
|
ember.m_Supersample = 1;
|
|
|
|
ember.m_SpatialFilterRadius = T(0.5);
|
|
|
|
ember.m_SpatialFilterType = GAUSSIAN_SPATIAL_FILTER;
|
|
|
|
ember.m_Zoom = 0;
|
|
|
|
ember.m_Quality = 1;
|
|
|
|
ember.m_TemporalSamples = 1;
|
|
|
|
ember.m_MaxRadDE = 0;
|
|
|
|
ember.m_MinRadDE = 0;
|
|
|
|
ember.m_CurveDE = T(0.6);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The core of the EmberGenome.exe program.
|
|
|
|
/// Template argument expected to be float or double.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="opt">A populated EmberOptions object which specifies all program options to be used</param>
|
|
|
|
/// <returns>True if success, else false.</returns>
|
|
|
|
template <typename T, typename bucketT>
|
|
|
|
bool EmberGenome(EmberOptions& opt)
|
|
|
|
{
|
|
|
|
OpenCLWrapper wrapper;
|
|
|
|
std::cout.imbue(std::locale(""));
|
|
|
|
|
|
|
|
if (opt.DumpArgs())
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << opt.GetValues(OPT_USE_GENOME) << endl;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (opt.OpenCLInfo())
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "\nOpenCL Info: " << endl;
|
|
|
|
cerr << wrapper.DumpInfo();
|
2014-07-08 03:11:14 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Regular variables.
|
|
|
|
Timing t;
|
|
|
|
bool exactTimeMatch, randomMode, didColor, seqFlag;
|
2014-12-06 00:05:09 -05:00
|
|
|
uint i, j, i0, i1, rep, val, frame, frameCount, count = 0;
|
|
|
|
uint ftime, firstFrame, lastFrame;
|
2014-10-14 11:53:15 -04:00
|
|
|
size_t n, tot, totb, totw;
|
2014-07-08 03:11:14 -04:00
|
|
|
T avgPix, fractionBlack, fractionWhite, blend, spread, mix0, mix1;
|
|
|
|
string token, filename;
|
|
|
|
ostringstream os, os2;
|
|
|
|
vector<Ember<T>> embers, embers2, templateEmbers;
|
|
|
|
vector<eVariationId> vars, noVars;
|
2014-12-06 00:05:09 -05:00
|
|
|
vector<byte> finalImage;
|
2014-07-08 03:11:14 -04:00
|
|
|
eCrossMode crossMeth;
|
|
|
|
eMutateMode mutMeth;
|
|
|
|
Ember<T> orig, save, selp0, selp1, parent0, parent1;
|
|
|
|
Ember<T> result, result1, result2, result3, interpolated;
|
2014-12-05 21:30:46 -05:00
|
|
|
Ember<T>* aselp0, *aselp1, *pTemplate = nullptr;
|
2014-07-08 03:11:14 -04:00
|
|
|
XmlToEmber<T> parser;
|
|
|
|
EmberToXml<T> emberToXml;
|
|
|
|
VariationList<T> varList;
|
|
|
|
EmberReport emberReport, emberReport2;
|
2014-10-18 17:07:07 -04:00
|
|
|
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));
|
2014-07-08 03:11:14 -04:00
|
|
|
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();
|
|
|
|
|
|
|
|
os.imbue(std::locale(""));
|
|
|
|
os2.imbue(std::locale(""));
|
|
|
|
|
|
|
|
if (!errorReport.empty())
|
2015-01-23 21:26:18 -05:00
|
|
|
cerr << emberReport.ErrorReportString();
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
if (!renderer.get())
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Renderer creation failed, exiting." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!InitPaletteList<T>(opt.PalettePath()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!opt.EmberCL())
|
|
|
|
{
|
|
|
|
if (opt.ThreadCount() != 0)
|
2014-12-05 21:30:46 -05:00
|
|
|
renderer->ThreadCount(opt.ThreadCount(), opt.IsaacSeed() != "" ? opt.IsaacSeed().c_str() : nullptr);
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Using OpenCL to render." << endl;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (opt.Verbose())
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Platform: " << wrapper.PlatformName(opt.Platform()) << endl;
|
|
|
|
cerr << "Device: " << wrapper.DeviceName(opt.Platform(), opt.Device()) << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//SheepTools will own the created renderer and will take care of cleaning it up.
|
|
|
|
SheepTools<T, bucketT> tools(opt.PalettePath(), CreateRenderer<T, bucketT>(opt.EmberCL() ? OPENCL_RENDERER : CPU_RENDERER, opt.Platform(), opt.Device(), false, 0, emberReport2));
|
|
|
|
|
|
|
|
tools.SetSpinParams(!opt.UnsmoothEdge(),
|
|
|
|
T(opt.Stagger()),
|
|
|
|
T(opt.OffsetX()),
|
|
|
|
T(opt.OffsetY()),
|
|
|
|
opt.Nick(),
|
|
|
|
opt.Url(),
|
|
|
|
opt.Id(),
|
|
|
|
opt.Comment(),
|
|
|
|
opt.SheepGen(),
|
|
|
|
opt.SheepId());
|
|
|
|
|
|
|
|
if (opt.UseVars() != "" && opt.DontUseVars() != "")
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "use_vars and dont_use_vars cannot both be specified. Returning without executing." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Specify reasonable defaults if nothing is specified.
|
|
|
|
if (opt.UseVars() == "" && opt.DontUseVars() == "")
|
|
|
|
{
|
|
|
|
noVars.push_back(VAR_NOISE);
|
|
|
|
noVars.push_back(VAR_BLUR);
|
|
|
|
noVars.push_back(VAR_GAUSSIAN_BLUR);
|
|
|
|
noVars.push_back(VAR_RADIAL_BLUR);
|
|
|
|
noVars.push_back(VAR_NGON);
|
|
|
|
noVars.push_back(VAR_SQUARE);
|
|
|
|
noVars.push_back(VAR_RAYS);
|
|
|
|
noVars.push_back(VAR_CROSS);
|
|
|
|
noVars.push_back(VAR_PRE_BLUR);
|
|
|
|
noVars.push_back(VAR_SEPARATION);
|
|
|
|
noVars.push_back(VAR_SPLIT);
|
|
|
|
noVars.push_back(VAR_SPLITS);
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
//Loop over the novars and set ivars to the complement.
|
|
|
|
for (i = 0; i < varList.Size(); i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < noVars.size(); j++)
|
|
|
|
{
|
|
|
|
if (noVars[j] == varList.GetVariation(i)->VariationId())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == noVars.size())
|
|
|
|
vars.push_back(varList.GetVariation(i)->VariationId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (opt.UseVars() != "")//Parse comma-separated list of variations to use.
|
|
|
|
{
|
|
|
|
istringstream iss(opt.UseVars());
|
|
|
|
|
|
|
|
while (std::getline(iss, token, ','))
|
|
|
|
{
|
2014-12-07 02:51:44 -05:00
|
|
|
if (parser.Atoi(token.c_str(), val))
|
2014-07-08 03:11:14 -04:00
|
|
|
{
|
|
|
|
if (val < varList.Size())
|
2014-12-07 02:51:44 -05:00
|
|
|
vars.push_back(static_cast<eVariationId>(val));
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (opt.DontUseVars() != "")
|
|
|
|
{
|
|
|
|
istringstream iss(opt.DontUseVars());
|
|
|
|
|
|
|
|
while (std::getline(iss, token, ','))
|
|
|
|
{
|
2014-12-07 02:51:44 -05:00
|
|
|
if (parser.Atoi(token.c_str(), val))
|
2014-07-08 03:11:14 -04:00
|
|
|
{
|
|
|
|
if (val < varList.Size())
|
2014-12-07 02:51:44 -05:00
|
|
|
noVars.push_back(static_cast<eVariationId>(val));
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Loop over the novars and set ivars to the complement.
|
|
|
|
for (i = 0; i < varList.Size(); i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < noVars.size(); j++)
|
|
|
|
{
|
|
|
|
if (noVars[j] == varList.GetVariation(i)->VariationId())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == noVars.size())
|
|
|
|
vars.push_back(varList.GetVariation(i)->VariationId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool doMutate = opt.Mutate() != "";
|
|
|
|
bool doInter = opt.Inter() != "";
|
|
|
|
bool doRotate = opt.Rotate() != "";
|
|
|
|
bool doClone = opt.Clone() != "";
|
|
|
|
bool doStrip = opt.Strip() != "";
|
|
|
|
bool doCross0 = opt.Cross0() != "";
|
|
|
|
bool doCross1 = opt.Cross1() != "";
|
|
|
|
|
|
|
|
count += (doMutate ? 1 : 0);
|
|
|
|
count += (doInter ? 1 : 0);
|
|
|
|
count += (doRotate ? 1 : 0);
|
|
|
|
count += (doClone ? 1 : 0);
|
|
|
|
count += (doStrip ? 1 : 0);
|
|
|
|
count += ((doCross0 || doCross1) ? 1 : 0);
|
|
|
|
|
|
|
|
if (count > 1)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Can only specify one of mutate, clone, cross, rotate, strip, or inter. Returning without executing." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-23 21:26:18 -05:00
|
|
|
if (doCross0 != doCross1)//Must both be either true or false.
|
2014-07-08 03:11:14 -04:00
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Must specify both crossover arguments. Returning without executing." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Method() != "" && (!doCross0 && !doMutate))
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Cannot specify method unless doing crossover or mutate. Returning without executing." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.TemplateFile() != "")
|
|
|
|
{
|
|
|
|
if (!ParseEmberFile(parser, opt.TemplateFile(), templateEmbers))
|
|
|
|
return false;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (templateEmbers.size() > 1)
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "More than one control point in template, ignoring all but first." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
pTemplate = &templateEmbers[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
//Methods for genetic manipulation begin here.
|
|
|
|
if (doMutate) filename = opt.Mutate();
|
|
|
|
else if (doInter) filename = opt.Inter();
|
|
|
|
else if (doRotate) filename = opt.Rotate();
|
|
|
|
else if (doClone) filename = opt.Clone();
|
|
|
|
else if (doStrip) filename = opt.Strip();
|
|
|
|
else if (doCross0) filename = opt.Cross0();
|
|
|
|
else if (opt.CloneAll() != "") filename = opt.CloneAll();
|
|
|
|
else if (opt.Animate() != "") filename = opt.Animate();
|
|
|
|
else if (opt.Sequence() != "") filename = opt.Sequence();
|
|
|
|
else if (opt.Inter() != "") filename = opt.Inter();
|
|
|
|
else if (opt.Rotate() != "") filename = opt.Rotate();
|
|
|
|
else if (opt.Strip() != "") filename = opt.Strip();
|
|
|
|
else if (opt.Clone() != "") filename = opt.Clone();
|
|
|
|
else if (opt.Mutate() != "") filename = opt.Mutate();
|
|
|
|
|
2014-11-28 04:37:51 -05:00
|
|
|
if (ParseEmberFile(parser, filename, embers))
|
|
|
|
{
|
|
|
|
if (opt.SubBatchSize() != DEFAULT_SBS)
|
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
embers[i].m_SubBatchSize = opt.SubBatchSize();
|
|
|
|
}
|
|
|
|
else
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
|
2015-01-21 05:51:26 -05:00
|
|
|
if (doCross1)
|
2014-11-28 04:37:51 -05:00
|
|
|
{
|
2015-01-21 05:51:26 -05:00
|
|
|
if (ParseEmberFile(parser, opt.Cross1(), embers2))
|
|
|
|
{
|
|
|
|
if (opt.SubBatchSize() != DEFAULT_SBS)
|
|
|
|
for (i = 0; i < embers2.size(); i++)
|
|
|
|
embers2[i].m_SubBatchSize = opt.SubBatchSize();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
2014-11-28 04:37:51 -05:00
|
|
|
}
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
if (opt.CloneAll() != "")
|
|
|
|
{
|
|
|
|
cout << "<clone_all version=\"Ember-" << EmberVersion() << "\">" << endl;
|
|
|
|
|
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
{
|
|
|
|
if (pTemplate)
|
|
|
|
tools.ApplyTemplate(embers[i], *pTemplate);
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-12-07 02:51:44 -05:00
|
|
|
tools.Offset(embers[i], T(opt.OffsetX()), T(opt.OffsetY()));
|
2014-07-08 03:11:14 -04:00
|
|
|
cout << emberToXml.ToString(embers[i], opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
|
|
|
}
|
|
|
|
|
|
|
|
cout << "</clone_all>" << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Animate() != "")
|
|
|
|
{
|
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
{
|
|
|
|
if (i > 0 && embers[i].m_Time <= embers[i - 1].m_Time)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Error: control points must be sorted by time, but " << embers[i].m_Time << " <= " << embers[i - 1].m_Time << ", index " << i << "." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
embers[i].DeleteMotionElements();
|
|
|
|
}
|
|
|
|
|
2014-12-07 02:51:44 -05:00
|
|
|
firstFrame = uint(opt.FirstFrame() == UINT_MAX ? embers[0].m_Time : opt.FirstFrame());
|
|
|
|
lastFrame = uint(opt.LastFrame() == UINT_MAX ? embers.back().m_Time : opt.LastFrame());
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
if (lastFrame < firstFrame)
|
|
|
|
lastFrame = firstFrame;
|
|
|
|
|
|
|
|
cout << "<animate version=\"EMBER-" << EmberVersion() << "\">" << endl;
|
|
|
|
|
|
|
|
for (ftime = firstFrame; ftime <= lastFrame; ftime++)
|
|
|
|
{
|
|
|
|
exactTimeMatch = false;
|
|
|
|
|
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
{
|
2014-12-07 02:51:44 -05:00
|
|
|
if (ftime == uint(embers[i].m_Time))
|
2014-07-08 03:11:14 -04:00
|
|
|
{
|
|
|
|
interpolated = embers[i];
|
|
|
|
exactTimeMatch = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!exactTimeMatch)
|
|
|
|
{
|
|
|
|
Interpolater<T>::Interpolate(embers, T(ftime), T(opt.Stagger()), interpolated);
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
{
|
2014-12-07 02:51:44 -05:00
|
|
|
if (ftime == uint(embers[i].m_Time - 1))
|
2014-07-08 03:11:14 -04:00
|
|
|
{
|
|
|
|
exactTimeMatch = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!exactTimeMatch)
|
|
|
|
interpolated.m_AffineInterp = INTERP_LINEAR;
|
|
|
|
}
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (pTemplate)
|
|
|
|
tools.ApplyTemplate(interpolated, *pTemplate);
|
|
|
|
|
|
|
|
cout << emberToXml.ToString(interpolated, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
|
|
|
}
|
|
|
|
|
|
|
|
cout << "</animate>" << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Sequence() != "")
|
|
|
|
{
|
|
|
|
frame = std::max(opt.Frame(), opt.Time());
|
|
|
|
|
|
|
|
if (opt.Frames() == 0)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "nframes must be positive and non-zero, not " << opt.Frames() << "." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "<sequence version=\"EMBER-" << EmberVersion() << "\">" << endl;
|
|
|
|
|
|
|
|
spread = 1 / T(opt.Frames());
|
|
|
|
frameCount = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
{
|
|
|
|
if (opt.Loops())
|
|
|
|
{
|
|
|
|
for (frame = 0; frame < opt.Frames(); frame++)
|
|
|
|
{
|
2014-12-07 02:51:44 -05:00
|
|
|
blend = T(frame) / T(opt.Frames());
|
2014-07-08 03:11:14 -04:00
|
|
|
tools.Spin(embers[i], pTemplate, result, frameCount++, blend);//Result is cleared and reassigned each time inside of Spin().
|
|
|
|
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < embers.size() - 1)
|
|
|
|
{
|
|
|
|
for (frame = 0; frame < opt.Frames(); frame++)
|
|
|
|
{
|
|
|
|
seqFlag = (frame == 0 || frame == opt.Frames() - 1);
|
2014-12-07 02:51:44 -05:00
|
|
|
blend = frame / T(opt.Frames());
|
2014-07-08 03:11:14 -04:00
|
|
|
result.Clear();
|
|
|
|
tools.SpinInter(&embers[i], pTemplate, result, frameCount++, seqFlag, blend);
|
|
|
|
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = embers.back();
|
|
|
|
tools.Spin(embers.back(), pTemplate, result, frameCount, 0);
|
|
|
|
cout << emberToXml.ToString(result, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "</sequence>" << endl;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doInter || doRotate)
|
|
|
|
{
|
|
|
|
frame = std::max(opt.Frame(), opt.Time());
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (opt.Frames() == 0)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "nframes must be positive and non-zero, not " << opt.Frames() << "." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
blend = frame / T(opt.Frames());
|
|
|
|
spread = 1 / T(opt.Frames());
|
|
|
|
|
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "<pick version=\"EMBER-" << EmberVersion() << "\">" << endl;
|
|
|
|
|
|
|
|
if (doRotate)
|
|
|
|
{
|
|
|
|
if (embers.size() != 1)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "rotation requires one control point, not " << embers.size() << "." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (embers.size() != 2)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "interpolation requires two control points, not " << embers.size() << "." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "</pick>" << endl;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doStrip)
|
|
|
|
{
|
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "<pick version=\"EMBER-" << EmberVersion() << "\">" << endl;
|
|
|
|
|
|
|
|
for (i = 0; i < embers.size(); i++)
|
|
|
|
{
|
|
|
|
T oldX, oldY;
|
|
|
|
|
|
|
|
embers[i].DeleteMotionElements();
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
oldX = embers[i].m_CenterX;
|
|
|
|
oldY = embers[i].m_CenterY;
|
2014-12-07 02:51:44 -05:00
|
|
|
embers[i].m_FinalRasH = uint(T(embers[i].m_FinalRasH) / T(opt.Frames()));
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
embers[i].m_CenterY = embers[i].m_CenterY - ((opt.Frames() - 1) * embers[i].m_FinalRasH) /
|
|
|
|
(2 * embers[i].m_PixelsPerUnit * pow(T(2.0), embers[i].m_Zoom));
|
|
|
|
embers[i].m_CenterY += embers[i].m_FinalRasH * opt.Frame() / (embers[i].m_PixelsPerUnit * pow(T(2.0), embers[i].m_Zoom));
|
|
|
|
|
|
|
|
tools.RotateOldCenterBy(embers[i].m_CenterX, embers[i].m_CenterY, oldX, oldY, embers[i].m_Rotate);
|
|
|
|
|
|
|
|
if (pTemplate)
|
|
|
|
tools.ApplyTemplate(embers[i], *pTemplate);
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
tools.Offset(embers[i], T(opt.OffsetX()), T(opt.OffsetY()));
|
|
|
|
cout << emberToXml.ToString(embers[i], opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "</pick>" << endl;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Repeat.
|
|
|
|
renderer->EarlyClip(opt.EarlyClip());
|
2014-08-06 00:50:52 -04:00
|
|
|
renderer->YAxisUp(opt.YAxisUp());
|
|
|
|
renderer->LockAccum(opt.LockAccum());
|
2014-07-08 03:11:14 -04:00
|
|
|
renderer->PixelAspectRatio(T(opt.AspectRatio()));
|
2014-08-06 00:50:52 -04:00
|
|
|
renderer->Transparency(opt.Transparency());
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
if (opt.Repeat() == 0)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Repeat must be positive, not " << opt.Repeat() << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Enclosed())
|
2015-01-23 21:26:18 -05:00
|
|
|
cout << "<pick version=\"EMBER-" << EmberVersion() << "\">" << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
for (rep = 0; rep < opt.Repeat(); rep++)
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
os.str("");
|
|
|
|
save.Clear();
|
|
|
|
VerbosePrint("Flame = " << rep + 1 << "/" << opt.Repeat() << "..");
|
|
|
|
|
|
|
|
if (opt.Clone() != "")
|
|
|
|
{
|
|
|
|
os << "clone";//Action is 'clone' with trunc vars concat.
|
|
|
|
|
|
|
|
if (opt.CloneAction() != "")
|
|
|
|
os << " " << opt.CloneAction();
|
|
|
|
|
|
|
|
selp0 = embers[rand.Rand() % embers.size()];
|
|
|
|
save = selp0;
|
|
|
|
aselp0 = &selp0;
|
2014-12-05 21:30:46 -05:00
|
|
|
aselp1 = nullptr;
|
2014-07-08 03:11:14 -04:00
|
|
|
os << tools.TruncateVariations(save, 5);
|
|
|
|
save.m_Edits = emberToXml.CreateNewEditdoc(aselp0, aselp1, os.str(), opt.Nick(), opt.Url(), opt.Id(), opt.Comment(), opt.SheepGen(), opt.SheepId());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
randomMode = false;
|
|
|
|
didColor = false;
|
|
|
|
os.str("");
|
|
|
|
VerbosePrint(".");
|
|
|
|
|
|
|
|
if (doMutate)
|
|
|
|
{
|
|
|
|
selp0 = embers[rand.Rand() % embers.size()];
|
|
|
|
orig = selp0;
|
|
|
|
aselp0 = &selp0;
|
2014-12-05 21:30:46 -05:00
|
|
|
aselp1 = nullptr;
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
if (opt.Method() == "")
|
|
|
|
mutMeth = MUTATE_NOT_SPECIFIED;
|
|
|
|
else if (opt.Method() == "all_vars")
|
|
|
|
mutMeth = MUTATE_ALL_VARIATIONS;
|
|
|
|
else if (opt.Method() == "one_xform")
|
|
|
|
mutMeth = MUTATE_ONE_XFORM_COEFS;
|
|
|
|
else if (opt.Method() == "add_symmetry")
|
|
|
|
mutMeth = MUTATE_ADD_SYMMETRY;
|
|
|
|
else if (opt.Method() == "post_xforms")
|
|
|
|
mutMeth = MUTATE_POST_XFORMS;
|
|
|
|
else if (opt.Method() == "color_palette")
|
|
|
|
mutMeth = MUTATE_COLOR_PALETTE;
|
|
|
|
else if (opt.Method() == "delete_xform")
|
|
|
|
mutMeth = MUTATE_DELETE_XFORM;
|
|
|
|
else if (opt.Method() == "all_coefs")
|
|
|
|
mutMeth = MUTATE_ALL_COEFS;
|
|
|
|
else
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "method " << opt.Method() << " not defined for mutate. Defaulting to random." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
mutMeth = MUTATE_NOT_SPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
os << tools.Mutate(orig, mutMeth, vars, opt.Symmetry(), T(opt.Speed()));
|
|
|
|
|
|
|
|
//Scan string returned for 'mutate color'.
|
|
|
|
if (strstr(os.str().c_str(), "mutate color"))
|
|
|
|
didColor = true;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (orig.m_Name != "")
|
|
|
|
{
|
|
|
|
os2.str("");
|
|
|
|
os2 << "mutation " << rep << " of " << orig.m_Name;
|
|
|
|
orig.m_Name = os2.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (doCross0)
|
|
|
|
{
|
|
|
|
i0 = rand.Rand() % embers.size();
|
|
|
|
i1 = rand.Rand() % embers2.size();
|
|
|
|
|
|
|
|
selp0 = embers[i0];
|
|
|
|
selp1 = embers2[i1];
|
|
|
|
|
|
|
|
aselp0 = &selp0;
|
|
|
|
aselp1 = &selp1;
|
|
|
|
|
|
|
|
if (opt.Method() == "")
|
|
|
|
crossMeth = CROSS_NOT_SPECIFIED;
|
|
|
|
else if (opt.Method() == "union")
|
|
|
|
crossMeth = CROSS_UNION;
|
|
|
|
else if (opt.Method() == "interpolate")
|
|
|
|
crossMeth = CROSS_INTERPOLATE;
|
|
|
|
else if (opt.Method() == "alternate")
|
|
|
|
crossMeth = CROSS_ALTERNATE;
|
|
|
|
else
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "method '" << opt.Method() << "' not defined for cross. Defaulting to random." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
crossMeth = CROSS_NOT_SPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
tools.Cross(embers[i0], embers2[i1], orig, crossMeth);
|
|
|
|
|
|
|
|
if (embers[i0].m_Name != "" || embers2[i1].m_Name != "")
|
|
|
|
{
|
|
|
|
os2.str("");
|
|
|
|
os2 << rep << " of " << embers[i0].m_Name << " x " << embers2[i1].m_Name;
|
|
|
|
orig.m_Name = os2.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
os << "random";
|
|
|
|
randomMode = true;
|
|
|
|
tools.Random(orig, vars, opt.Symmetry(), 0);
|
2014-12-05 21:30:46 -05:00
|
|
|
aselp0 = nullptr;
|
|
|
|
aselp1 = nullptr;
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
//Adjust bounding box half the time.
|
|
|
|
if (rand.RandBit() || randomMode)
|
|
|
|
{
|
|
|
|
T bmin[2], bmax[2];
|
|
|
|
tools.EstimateBoundingBox(orig, T(0.01), 100000, bmin, bmax);
|
|
|
|
|
|
|
|
if (rand.Frand01<T>() < T(0.3))
|
|
|
|
{
|
|
|
|
orig.m_CenterX = (bmin[0] + bmax[0]) / 2;
|
|
|
|
orig.m_CenterY = (bmin[1] + bmax[1]) / 2;
|
|
|
|
os << " recentered";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rand.RandBit())
|
|
|
|
{
|
|
|
|
mix0 = rand.GoldenBit<T>() + rand.Frand11<T>() / 5;
|
|
|
|
mix1 = rand.GoldenBit<T>();
|
|
|
|
os << " reframed0";
|
|
|
|
}
|
|
|
|
else if (rand.RandBit())
|
|
|
|
{
|
|
|
|
mix0 = rand.GoldenBit<T>();
|
|
|
|
mix1 = rand.GoldenBit<T>() + rand.Frand11<T>() / 5;
|
|
|
|
os << " reframed1";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mix0 = rand.GoldenBit<T>() + rand.Frand11<T>() / 5;
|
|
|
|
mix1 = rand.GoldenBit<T>() + rand.Frand11<T>() / 5;
|
|
|
|
os << " reframed2";
|
|
|
|
}
|
|
|
|
|
|
|
|
orig.m_CenterX = mix0 * bmin[0] + (1 - mix0) * bmax[0];
|
|
|
|
orig.m_CenterY = mix1 * bmin[1] + (1 - mix1) * bmax[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
orig.m_PixelsPerUnit = orig.m_FinalRasW / (bmax[0] - bmin[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
os << tools.TruncateVariations(orig, 5);
|
|
|
|
|
|
|
|
if (!didColor && rand.RandBit())
|
|
|
|
{
|
|
|
|
if (opt.Debug())
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "improving colors..." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
tools.ImproveColors(orig, 100, false, 10);
|
|
|
|
os << " improved colors";
|
|
|
|
}
|
|
|
|
|
|
|
|
orig.m_Edits = emberToXml.CreateNewEditdoc(aselp0, aselp1, os.str(), opt.Nick(), opt.Url(), opt.Id(), opt.Comment(), opt.SheepGen(), opt.SheepId());
|
|
|
|
save = orig;
|
|
|
|
SetDefaultTestValues(orig);
|
|
|
|
renderer->SetEmber(orig);
|
|
|
|
|
|
|
|
if (renderer->Run(finalImage) != RENDER_OK)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Error: test image rendering failed, aborting." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
tot = totb = totw = 0;
|
|
|
|
n = orig.m_FinalRasW * orig.m_FinalRasH;
|
|
|
|
|
|
|
|
for (i = 0; i < 3 * n; i += 3)
|
|
|
|
{
|
|
|
|
tot += (finalImage[i] + finalImage[i + 1] + finalImage[i + 2]);
|
|
|
|
|
|
|
|
if (0 == finalImage[i] && 0 == finalImage[i + 1] && 0 == finalImage[i + 2]) totb++;
|
|
|
|
if (255 == finalImage[i] && 255 == finalImage[i + 1] && 255 == finalImage[i + 2]) totw++;
|
|
|
|
}
|
|
|
|
|
|
|
|
avgPix = (tot / T(3 * n));
|
|
|
|
fractionBlack = totb / T(n);
|
|
|
|
fractionWhite = totw / T(n);
|
|
|
|
|
|
|
|
if (opt.Debug())
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "avgPix = " << avgPix << " fractionBlack = " << fractionBlack << " fractionWhite = " << fractionWhite << " n = " << n << endl;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
orig.Clear();
|
|
|
|
count++;
|
|
|
|
} while ((avgPix < opt.AvgThresh() ||
|
|
|
|
fractionBlack < opt.BlackThresh() ||
|
|
|
|
fractionWhite > opt.WhiteLimit()) &&
|
|
|
|
count < opt.Tries());
|
|
|
|
|
|
|
|
if (count == opt.Tries())
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Warning: reached maximum attempts, giving up." << endl;
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pTemplate)
|
|
|
|
tools.ApplyTemplate(save, *pTemplate);
|
|
|
|
|
|
|
|
save.m_Time = T(rep);
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
if (opt.MaxXforms() != UINT_MAX)
|
|
|
|
{
|
|
|
|
save.m_Symmetry = 0;
|
|
|
|
|
|
|
|
while (save.TotalXformCount() > opt.MaxXforms())
|
|
|
|
save.DeleteTotalXform(save.TotalXformCount() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
cout << emberToXml.ToString(save, opt.Extras(), opt.PrintEditDepth(), !opt.NoEdits(), false, opt.HexPalette());
|
|
|
|
VerbosePrint("\nDone. Action = " << os.str() << "\n");
|
|
|
|
cout.flush();
|
|
|
|
save.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opt.Enclosed())
|
|
|
|
cout << "</pick>\n";
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Main program entry point for EmberGenome.exe.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="argc">The number of command line arguments passed</param>
|
|
|
|
/// <param name="argv">The command line arguments passed</param>
|
|
|
|
/// <returns>0 if successful, else 1.</returns>
|
|
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
|
|
{
|
2014-12-05 21:30:46 -05:00
|
|
|
bool b = false;
|
2014-07-08 03:11:14 -04:00
|
|
|
EmberOptions opt;
|
2014-12-05 21:30:46 -05:00
|
|
|
|
2014-07-08 03:11:14 -04:00
|
|
|
//Required for large allocs, else GPU memory usage will be severely limited to small sizes.
|
|
|
|
//This must be done in the application and not in the EmberCL DLL.
|
2014-12-05 21:30:46 -05:00
|
|
|
#ifdef WIN32
|
2014-07-08 03:11:14 -04:00
|
|
|
_putenv_s("GPU_MAX_ALLOC_PERCENT", "100");
|
2014-12-05 21:30:46 -05:00
|
|
|
#else
|
2014-12-07 02:51:44 -05:00
|
|
|
putenv(const_cast<char*>("GPU_MAX_ALLOC_PERCENT=100"));
|
2014-12-05 21:30:46 -05:00
|
|
|
#endif
|
2014-07-08 03:11:14 -04:00
|
|
|
|
2014-12-05 21:30:46 -05:00
|
|
|
if (!opt.Populate(argc, argv, OPT_USE_GENOME))
|
|
|
|
{
|
2014-07-08 03:11:14 -04:00
|
|
|
|
|
|
|
#ifdef DO_DOUBLE
|
2014-12-05 21:30:46 -05:00
|
|
|
if (opt.Bits() == 64)
|
|
|
|
{
|
|
|
|
b = EmberGenome<double, double>(opt);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (opt.Bits() == 33)
|
|
|
|
{
|
|
|
|
b = EmberGenome<float, float>(opt);
|
|
|
|
}
|
|
|
|
else if (opt.Bits() == 32)
|
|
|
|
{
|
2015-01-21 08:34:34 -05:00
|
|
|
cerr << "Bits 32/int histogram no longer supported. Using bits == 33 (float)." << endl;
|
2014-12-05 21:30:46 -05:00
|
|
|
b = EmberGenome<float, float>(opt);
|
|
|
|
}
|
2014-07-08 03:11:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return b ? 0 : 1;
|
2014-12-05 21:30:46 -05:00
|
|
|
}
|