#pragma once
#include "EmberCommonPch.h"
///
/// Global utility classes and functions that are common to all programs that use
/// Ember and its derivatives.
///
///
/// Derivation of the RenderCallback class to do custom printing action
/// whenever the progress function is internally called inside of Ember
/// and its derivatives.
/// Template argument expected to be float or double.
///
template
class RenderProgress : public RenderCallback
{
public:
///
/// Constructor that initializes the state to zero.
///
RenderProgress()
{
Clear();
}
///
/// The progress function which will be called from inside the renderer.
///
/// The ember currently being rendered
/// An extra dummy parameter
/// The progress fraction from 0-100
/// The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.
/// The estimated milliseconds to completion of the current stage
/// 1 since this is intended to run in an environment where the render runs to completion, unlike interactive rendering.
virtual int ProgressFunc(Ember& ember, void* foo, double fraction, int stage, double etaMs)
{
if (stage == 0 || stage == 1)
{
if (m_LastStage != stage)
cout << endl;
cout << "\r" << string(m_S.length() * 2, ' ');//Clear what was previously here, * 2 just to be safe because the end parts of previous strings might be longer.
m_SS.str("");//Begin new output.
m_SS << "\rStage = " << (stage ? "filtering" : "chaos");
m_SS << ", progress = " << int(fraction) << "%";
m_SS << ", eta = " << t.Format(etaMs);
m_S = m_SS.str();
cout << m_S;
}
m_LastStage = stage;
return 1;
}
///
/// Reset the state.
///
void Clear()
{
m_LastStage = 0;
m_LastLength = 0;
m_SS.clear();
m_S.clear();
}
private:
int m_LastStage;
int m_LastLength;
stringstream m_SS;
string m_S;
Timing t;
};
///
/// Wrapper for parsing an ember Xml file, storing the embers in a vector and printing
/// any errors that occurred.
/// Template argument expected to be float or double.
///
/// The parser to use
/// The full path and name of the file
/// Storage for the embers read from the file
/// True if success, else false.
template
static bool ParseEmberFile(XmlToEmber& parser, string filename, vector>& embers)
{
if (!parser.Parse(filename.c_str(), embers))
{
cout << "Error parsing flame file " << filename << ", returning without executing." << endl;
return false;
}
if (embers.empty())
{
cout << "Error: No data present in file " << filename << ". Aborting." << endl;
return false;
}
return true;
}
///
/// Wrapper for parsing palette Xml file and initializing it's private static members,
/// and printing any errors that occurred.
/// Template argument expected to be float or double.
///
/// The full path and name of the file
/// True if success, else false.
template
static bool InitPaletteList(string filename)
{
PaletteList paletteList;//Even though this is local, the members are static so they will remain.
if (!paletteList.Init(filename))
{
cout << "Error parsing palette file " << filename << ". Reason: " << endl;
cout << paletteList.ErrorReportString() << endl << "Returning without executing." << endl;
return false;
}
return true;
}
///
/// Calculate the number of strips required if the needed amount of memory
/// is greater than the system memory, or greater than what the user want to allow.
///
/// Amount of memory required
/// The maximum amount of memory to use. Use max if 0.
/// The number of strips to use
static unsigned int CalcStrips(double mem, double memAvailable, double useMem)
{
unsigned int strips;
double memRequired;
if (useMem > 0)
memAvailable = useMem;
else
memAvailable *= 0.8;
memRequired = mem;
if (memAvailable >= memRequired)
return 1;
strips = (unsigned int)ceil(memRequired / memAvailable);
return strips;
}
///
/// Given a numerator and a denominator, find the next highest denominator that divides
/// evenly into the numerator.
///
/// The numerator
/// The denominator
/// The next highest divisor if found, else 1.
static unsigned int NextHighestEvenDiv(unsigned int numerator, unsigned int denominator)
{
unsigned int result = 1;
unsigned int numDiv2 = numerator / 2;
do
{
denominator++;
if (numerator % denominator == 0)
{
result = denominator;
break;
}
}
while (denominator <= numDiv2);
return result;
}
///
/// Given a numerator and a denominator, find the next lowest denominator that divides
/// evenly into the numerator.
///
/// The numerator
/// The denominator
/// The next lowest divisor if found, else 1.
static unsigned int NextLowestEvenDiv(unsigned int numerator, unsigned int denominator)
{
unsigned int result = 1;
unsigned int numDiv2 = numerator / 2;
denominator--;
if (denominator > numDiv2)
denominator = numDiv2;
while (denominator >= 1)
{
if (numerator % denominator == 0)
{
result = denominator;
break;
}
denominator--;
}
return result;
}
///
/// Wrapper for creating a renderer of the specified type.
/// First template argument expected to be float or double for CPU renderer,
/// Second argument expected to be float or double for CPU renderer, and only float for OpenCL renderer.
///
/// Type of renderer to create
/// The index platform of the platform to use
/// The index device of the device to use
/// True if shared with OpenGL, else false.
/// The texture ID of the shared OpenGL texture if shared
/// The error report for holding errors if anything goes wrong
/// A pointer to the created renderer if successful, else false.
template
static Renderer* CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared, GLuint texId, EmberReport& errorReport)
{
string s;
auto_ptr> renderer;
try
{
if (renderType == CPU_RENDERER)
{
s = "CPU";
renderer = auto_ptr>(new Renderer());
}
else if (renderType == OPENCL_RENDERER)
{
s = "OpenCL";
renderer = auto_ptr>(new RendererCL(platform, device, shared, texId));
if (!renderer.get() || !renderer->Ok())
{
if (renderer.get())
errorReport.AddToReport(renderer->ErrorReport());
errorReport.AddToReport("Error initializing OpenCL renderer, using CPU renderer instead.");
renderer = auto_ptr>(new Renderer());
}
}
}
catch (...)
{
errorReport.AddToReport("Error creating " + s + " renderer.\n");
}
return renderer.release();
}
///
/// Simple macro to print a string if the --verbose options has been specified.
///
#define VerbosePrint(s) if (opt.Verbose()) cout << s << endl