mirror of
https://bitbucket.org/mfeemster/fractorium.git
synced 2025-08-17 04:44:56 -04:00
Initial source commit
Initial source commit
This commit is contained in:
261
Source/EmberCommon/EmberCommon.h
Normal file
261
Source/EmberCommon/EmberCommon.h
Normal file
@ -0,0 +1,261 @@
|
||||
#pragma once
|
||||
|
||||
#include "EmberCommonPch.h"
|
||||
|
||||
/// <summary>
|
||||
/// Global utility classes and functions that are common to all programs that use
|
||||
/// Ember and its derivatives.
|
||||
/// </summary>
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
template <typename T>
|
||||
class RenderProgress : public RenderCallback
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Constructor that initializes the state to zero.
|
||||
/// </summary>
|
||||
RenderProgress()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The progress function which will be called from inside the renderer.
|
||||
/// </summary>
|
||||
/// <param name="ember">The ember currently being rendered</param>
|
||||
/// <param name="foo">An extra dummy parameter</param>
|
||||
/// <param name="fraction">The progress fraction from 0-100</param>
|
||||
/// <param name="stage">The stage of iteration. 1 is iterating, 2 is density filtering, 2 is final accumulation.</param>
|
||||
/// <param name="etaMs">The estimated milliseconds to completion of the current stage</param>
|
||||
/// <returns>1 since this is intended to run in an environment where the render runs to completion, unlike interactive rendering.</returns>
|
||||
virtual int ProgressFunc(Ember<T>& 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(), ' ');//Clear what was previously here.
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the state.
|
||||
/// </summary>
|
||||
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;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="parser">The parser to use</param>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="embers">Storage for the embers read from the file</param>
|
||||
/// <returns>True if success, else false.</returns>
|
||||
template <typename T>
|
||||
static bool ParseEmberFile(XmlToEmber<T>& parser, string filename, vector<Ember<T>>& 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <returns>True if success, else false.</returns>
|
||||
template <typename T>
|
||||
static bool InitPaletteList(string filename)
|
||||
{
|
||||
PaletteList<T> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="mem">Amount of memory required</param>
|
||||
/// <param name="useMem">The maximum amount of memory to use. Use max if 0.</param>
|
||||
/// <returns>The number of strips to use</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a numerator and a denominator, find the next highest denominator that divides
|
||||
/// evenly into the numerator.
|
||||
/// </summary>
|
||||
/// <param name="numerator">The numerator</param>
|
||||
/// <param name="denominator">The denominator</param>
|
||||
/// <returns>The next highest divisor if found, else 1.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a numerator and a denominator, find the next lowest denominator that divides
|
||||
/// evenly into the numerator.
|
||||
/// </summary>
|
||||
/// <param name="numerator">The numerator</param>
|
||||
/// <param name="denominator">The denominator</param>
|
||||
/// <returns>The next lowest divisor if found, else 1.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="renderType">Type of renderer to create</param>
|
||||
/// <param name="platform">The index platform of the platform to use</param>
|
||||
/// <param name="device">The index device of the device to use</param>
|
||||
/// <param name="shared">True if shared with OpenGL, else false.</param>
|
||||
/// <param name="texId">The texture ID of the shared OpenGL texture if shared</param>
|
||||
/// <param name="errorReport">The error report for holding errors if anything goes wrong</param>
|
||||
/// <returns>A pointer to the created renderer if successful, else false.</returns>
|
||||
template <typename T, typename bucketT>
|
||||
static Renderer<T, bucketT>* CreateRenderer(eRendererType renderType, unsigned int platform, unsigned int device, bool shared, GLuint texId, EmberReport& errorReport)
|
||||
{
|
||||
string s;
|
||||
auto_ptr<Renderer<T, bucketT>> renderer;
|
||||
|
||||
try
|
||||
{
|
||||
if (renderType == CPU_RENDERER)
|
||||
{
|
||||
s = "CPU";
|
||||
renderer = auto_ptr<Renderer<T, bucketT>>(new Renderer<T, bucketT>());
|
||||
}
|
||||
else if (renderType == OPENCL_RENDERER)
|
||||
{
|
||||
s = "OpenCL";
|
||||
renderer = auto_ptr<Renderer<T, bucketT>>(new RendererCL<T>(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<Renderer<T, bucketT>>(new Renderer<T, bucketT>());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
errorReport.AddToReport("Error creating " + s + " renderer.\n");
|
||||
}
|
||||
|
||||
return renderer.release();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple macro to print a string if the --verbose options has been specified.
|
||||
/// </summary>
|
||||
#define VerbosePrint(s) if (opt.Verbose()) cout << s << endl
|
1
Source/EmberCommon/EmberCommonPch.cpp
Normal file
1
Source/EmberCommon/EmberCommonPch.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "EmberCommonPch.h"
|
54
Source/EmberCommon/EmberCommonPch.h
Normal file
54
Source/EmberCommon/EmberCommonPch.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
/// <summary>
|
||||
/// Precompiled header file. Place all system includes here with appropriate #defines for different operating systems and compilers.
|
||||
/// </summary>
|
||||
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN//Exclude rarely-used stuff from Windows headers.
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <SDKDDKVer.h>
|
||||
#include <windows.h>
|
||||
#include <winsock.h>//For htons().
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <BaseTsd.h>
|
||||
#include <crtdbg.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include "jconfig.h"
|
||||
#include "jpeglib.h"
|
||||
|
||||
#include "png.h"
|
||||
//#include "pnginfo.h"
|
||||
|
||||
//Ember.
|
||||
#include "Ember.h"
|
||||
#include "Variation.h"
|
||||
#include "EmberToXml.h"
|
||||
#include "XmlToEmber.h"
|
||||
#include "PaletteList.h"
|
||||
#include "Iterator.h"
|
||||
#include "Renderer.h"
|
||||
#include "RendererCL.h"
|
||||
#include "SheepTools.h"
|
||||
|
||||
//Options.
|
||||
#include "SimpleGlob.h"
|
||||
#include "SimpleOpt.h"
|
||||
|
||||
using namespace EmberNs;
|
||||
using namespace EmberCLns;
|
705
Source/EmberCommon/EmberOptions.h
Normal file
705
Source/EmberCommon/EmberOptions.h
Normal file
@ -0,0 +1,705 @@
|
||||
#pragma once
|
||||
|
||||
#include "EmberCommon.h"
|
||||
|
||||
/// <summary>
|
||||
/// EmberOptionEntry and EmberOptions classes.
|
||||
/// </summary>
|
||||
|
||||
static char* DescriptionString = "Ember - Fractal flames C++ port and enhancement with OpenCL GPU support";
|
||||
|
||||
/// <summary>
|
||||
/// Enum for specifying which command line programs an option is meant to be used with.
|
||||
/// If an option is used with multiple programs, their values are ORed together.
|
||||
/// </summary>
|
||||
enum eOptionUse
|
||||
{
|
||||
OPT_USE_RENDER = 1,
|
||||
OPT_USE_ANIMATE = 1 << 1,
|
||||
OPT_USE_GENOME = 1 << 2,
|
||||
OPT_RENDER_ANIM = OPT_USE_RENDER | OPT_USE_ANIMATE,
|
||||
OPT_ANIM_GENOME = OPT_USE_ANIMATE | OPT_USE_GENOME,
|
||||
OPT_USE_ALL = OPT_USE_RENDER | OPT_USE_ANIMATE | OPT_USE_GENOME
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifiers for every available option across all programs.
|
||||
/// </summary>
|
||||
enum eOptionIDs
|
||||
{
|
||||
//Diagnostic args.
|
||||
OPT_HELP,
|
||||
OPT_VERSION,
|
||||
OPT_VERBOSE,
|
||||
OPT_DEBUG,
|
||||
OPT_DUMP_ARGS,
|
||||
OPT_PROGRESS,
|
||||
OPT_DUMP_OPENCL_INFO,
|
||||
|
||||
//Boolean args.
|
||||
OPT_OPENCL,
|
||||
OPT_EARLYCLIP,
|
||||
OPT_TRANSPARENCY,
|
||||
OPT_NAME_ENABLE,
|
||||
OPT_INT_PALETTE,
|
||||
OPT_HEX_PALETTE,
|
||||
OPT_INSERT_PALETTE,
|
||||
OPT_JPEG_COMMENTS,
|
||||
OPT_PNG_COMMENTS,
|
||||
OPT_WRITE_GENOME,
|
||||
OPT_ENCLOSED,
|
||||
OPT_NO_EDITS,
|
||||
OPT_UNSMOOTH_EDGE,
|
||||
OPT_LOCK_ACCUM,
|
||||
OPT_DUMP_KERNEL,
|
||||
|
||||
//Value args.
|
||||
OPT_OPENCL_PLATFORM,//Int value args.
|
||||
OPT_OPENCL_DEVICE,
|
||||
OPT_SEED,
|
||||
OPT_NTHREADS,
|
||||
OPT_STRIPS,
|
||||
OPT_BITS,
|
||||
OPT_BPC,
|
||||
OPT_SBS,
|
||||
OPT_PRINT_EDIT_DEPTH,
|
||||
OPT_JPEG,
|
||||
OPT_BEGIN,
|
||||
OPT_END,
|
||||
OPT_FRAME,
|
||||
OPT_TIME,
|
||||
OPT_DTIME,
|
||||
OPT_NFRAMES,
|
||||
OPT_SYMMETRY,
|
||||
OPT_SHEEP_GEN,
|
||||
OPT_SHEEP_ID,
|
||||
OPT_LOOPS,
|
||||
OPT_REPEAT,
|
||||
OPT_TRIES,
|
||||
OPT_MAX_XFORMS,
|
||||
|
||||
OPT_SS,//Float value args.
|
||||
OPT_QS,
|
||||
OPT_PIXEL_ASPECT,
|
||||
OPT_STAGGER,
|
||||
OPT_AVG_THRESH,
|
||||
OPT_BLACK_THRESH,
|
||||
OPT_WHITE_LIMIT,
|
||||
OPT_SPEED,
|
||||
OPT_OFFSETX,
|
||||
OPT_OFFSETY,
|
||||
OPT_USEMEM,
|
||||
|
||||
OPT_ISAAC_SEED,//String value args.
|
||||
OPT_IN,
|
||||
OPT_OUT,
|
||||
OPT_PREFIX,
|
||||
OPT_SUFFIX,
|
||||
OPT_FORMAT,
|
||||
OPT_PALETTE_FILE,
|
||||
OPT_PALETTE_IMAGE,
|
||||
OPT_ID,
|
||||
OPT_URL,
|
||||
OPT_NICK,
|
||||
OPT_COMMENT,
|
||||
OPT_TEMPLATE,
|
||||
OPT_CLONE,
|
||||
OPT_CLONE_ALL,
|
||||
OPT_CLONE_ACTION,
|
||||
OPT_ANIMATE,
|
||||
OPT_MUTATE,
|
||||
OPT_CROSS0,
|
||||
OPT_CROSS1,
|
||||
OPT_METHOD,
|
||||
OPT_INTER,
|
||||
OPT_ROTATE,
|
||||
OPT_STRIP,
|
||||
OPT_SEQUENCE,
|
||||
OPT_USE_VARS,
|
||||
OPT_DONT_USE_VARS,
|
||||
OPT_EXTRAS
|
||||
};
|
||||
|
||||
class EmberOptions;
|
||||
|
||||
/// <summary>
|
||||
/// A single option.
|
||||
/// Template argument expected to be bool, int, unsigned int, double or string.
|
||||
/// </summary>
|
||||
template <typename T>
|
||||
class EmberOptionEntry
|
||||
{
|
||||
friend class EmberOptions;
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// Default constructor. This should never be used, instead use the one that takes arguments.
|
||||
/// </summary>
|
||||
EmberOptionEntry()
|
||||
{
|
||||
m_OptionUse = OPT_USE_ALL;
|
||||
m_Option.nArgType = SO_NONE;
|
||||
m_Option.nId = 0;
|
||||
m_Option.pszArg = _T("--fillmein");
|
||||
m_DocString = "Dummy doc";
|
||||
}
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Constructor that takes arguments.
|
||||
/// </summary>
|
||||
/// <param name="optUsage">The specified program usage</param>
|
||||
/// <param name="optId">The option identifier enum</param>
|
||||
/// <param name="arg">The command line argument (--arg)</param>
|
||||
/// <param name="defaultVal">The default value to use the option was not given on the command line</param>
|
||||
/// <param name="argType">The format the argument should be given in</param>
|
||||
/// <param name="docString">The documentation string describing what the argument means</param>
|
||||
EmberOptionEntry(eOptionUse optUsage, eOptionIDs optId, const CharT* arg, T defaultVal, ESOArgType argType, string docString)
|
||||
{
|
||||
m_OptionUse = optUsage;
|
||||
m_Option.nId = (int)optId;
|
||||
m_Option.pszArg = arg;
|
||||
m_Option.nArgType = argType;
|
||||
m_DocString = docString;
|
||||
m_NameWithoutDashes = Trim(string(arg), '-');
|
||||
m_Val = Arg<T>((char*)m_NameWithoutDashes.c_str(), defaultVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor.
|
||||
/// </summary>
|
||||
/// <param name="entry">The EmberOptionEntry object to copy</param>
|
||||
EmberOptionEntry(const EmberOptionEntry& entry)
|
||||
{
|
||||
*this = entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Functor accessors.
|
||||
/// </summary>
|
||||
inline T operator() (void) { return m_Val; }
|
||||
inline void operator() (T t) { m_Val = t; }
|
||||
|
||||
private:
|
||||
eOptionUse m_OptionUse;
|
||||
CSimpleOpt::SOption m_Option;
|
||||
string m_DocString;
|
||||
string m_NameWithoutDashes;
|
||||
T m_Val;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Macros for setting up and parsing various option types.
|
||||
/// </summary>
|
||||
|
||||
//Bool.
|
||||
#define Eob EmberOptionEntry<bool>
|
||||
#define INITBOOLOPTION(member, option) \
|
||||
member = option; \
|
||||
m_BoolArgs.push_back(&member)
|
||||
|
||||
#define PARSEBOOLOPTION(opt, member) \
|
||||
case (opt): \
|
||||
member(true); \
|
||||
break
|
||||
|
||||
//Int.
|
||||
#define Eoi EmberOptionEntry<int>
|
||||
#define INITINTOPTION(member, option) \
|
||||
member = option; \
|
||||
m_IntArgs.push_back(&member)
|
||||
|
||||
#define PARSEINTOPTION(opt, member) \
|
||||
case (opt): \
|
||||
sscanf_s(args.OptionArg(), "%d", &member.m_Val); \
|
||||
break
|
||||
|
||||
//Uint.
|
||||
#define Eou EmberOptionEntry<unsigned int>
|
||||
#define INITUINTOPTION(member, option) \
|
||||
member = option; \
|
||||
m_UintArgs.push_back(&member)
|
||||
|
||||
#define PARSEUINTOPTION(opt, member) \
|
||||
case (opt): \
|
||||
sscanf_s(args.OptionArg(), "%u", &member.m_Val); \
|
||||
break
|
||||
|
||||
//Double.
|
||||
#define Eod EmberOptionEntry<double>
|
||||
#define INITDOUBLEOPTION(member, option) \
|
||||
member = option; \
|
||||
m_DoubleArgs.push_back(&member)
|
||||
|
||||
#define PARSEDOUBLEOPTION(opt, member) \
|
||||
case (opt): \
|
||||
sscanf_s(args.OptionArg(), "%lf", &member.m_Val); \
|
||||
break
|
||||
|
||||
//String.
|
||||
#define Eos EmberOptionEntry<string>
|
||||
#define INITSTRINGOPTION(member, option) \
|
||||
member = option; \
|
||||
m_StringArgs.push_back(&member)
|
||||
|
||||
#define PARSESTRINGOPTION(opt, member) \
|
||||
case (opt): \
|
||||
member.m_Val = args.OptionArg(); \
|
||||
break
|
||||
|
||||
/// <summary>
|
||||
/// Class for holding all available options across all command line programs.
|
||||
/// Some are used only for a single program, while others are used for more than one.
|
||||
/// This prevents having to keep separate documentation strings around for different programs.
|
||||
/// </summary>
|
||||
class EmberOptions
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Constructor that populates all available options.
|
||||
/// </summary>
|
||||
EmberOptions()
|
||||
{
|
||||
m_BoolArgs.reserve(25);
|
||||
m_IntArgs.reserve(25);
|
||||
m_UintArgs.reserve(25);
|
||||
m_DoubleArgs.reserve(25);
|
||||
m_StringArgs.reserve(35);
|
||||
|
||||
//Diagnostic bools.
|
||||
INITBOOLOPTION(Help, Eob(OPT_USE_ALL, OPT_HELP, _T("--help"), false, SO_NONE, "\t--help Show this screen.\n"));
|
||||
INITBOOLOPTION(Version, Eob(OPT_USE_ALL, OPT_VERSION, _T("--version"), false, SO_NONE, "\t--version Show version.\n"));
|
||||
INITBOOLOPTION(Verbose, Eob(OPT_USE_ALL, OPT_VERBOSE, _T("--verbose"), false, SO_NONE, "\t--verbose Verbose output.\n"));
|
||||
INITBOOLOPTION(Debug, Eob(OPT_USE_ALL, OPT_DEBUG, _T("--debug"), false, SO_NONE, "\t--debug Debug output.\n"));
|
||||
INITBOOLOPTION(DumpArgs, Eob(OPT_USE_ALL, OPT_DUMP_ARGS, _T("--dumpargs"), false, SO_NONE, "\t--dumpargs Print all arguments entered from either the command line or environment variables.\n"));
|
||||
INITBOOLOPTION(DoProgress, Eob(OPT_USE_ALL, OPT_PROGRESS, _T("--progress"), false, SO_NONE, "\t--progress Display progress. This will slow down processing by about 10%%.\n"));
|
||||
INITBOOLOPTION(OpenCLInfo, Eob(OPT_USE_ALL, OPT_DUMP_OPENCL_INFO, _T("--openclinfo"), false, SO_NONE, "\t--openclinfo Display platforms and devices for OpenCL.\n"));
|
||||
|
||||
//Execution bools.
|
||||
INITBOOLOPTION(EmberCL, Eob(OPT_USE_ALL, OPT_OPENCL, _T("--opencl"), false, SO_NONE, "\t--opencl Use OpenCL renderer (EmberCL) for rendering [default: false].\n"));
|
||||
INITBOOLOPTION(EarlyClip, Eob(OPT_USE_ALL, OPT_EARLYCLIP, _T("--earlyclip"), false, SO_NONE, "\t--earlyclip Perform clipping of RGB values before spatial filtering for better antialiasing and resizing [default: false].\n"));
|
||||
INITBOOLOPTION(Transparency, Eob(OPT_RENDER_ANIM, 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(IntPalette, Eob(OPT_USE_ALL, 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(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(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(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(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(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 (ignored for OpenCL). This will drop performance to that of single threading [default: false].\n"));
|
||||
INITBOOLOPTION(DumpKernel, Eob(OPT_USE_RENDER, OPT_DUMP_KERNEL, _T("--dump_kernel"), false, SO_NONE, "\t--dump_kernel Print the iteration kernel string when using OpenCL (ignored for CPU) [default: false].\n"));
|
||||
|
||||
//Int.
|
||||
INITINTOPTION(Symmetry, Eoi(OPT_USE_GENOME, OPT_SYMMETRY, _T("--symmetry"), 0, SO_REQ_SEP, "\t--symmetry=<val> Set symmetry of result [default: 0].\n"));
|
||||
INITINTOPTION(SheepGen, Eoi(OPT_USE_GENOME, OPT_SHEEP_GEN, _T("--sheep_gen"), -1, SO_REQ_SEP, "\t--sheep_gen=<val> Sheep generation of this flame [default: -1].\n"));
|
||||
INITINTOPTION(SheepId, Eoi(OPT_USE_GENOME, OPT_SHEEP_ID, _T("--sheep_id"), -1, SO_REQ_SEP, "\t--sheep_id=<val> Sheep ID of this flame [default: -1].\n"));
|
||||
INITUINTOPTION(Platform, Eou(OPT_RENDER_ANIM, OPT_OPENCL_PLATFORM, _T("--platform"), 0, SO_REQ_SEP, "\t--platform The OpenCL platform index to use [default: 0].\n"));
|
||||
INITUINTOPTION(Device, Eou(OPT_RENDER_ANIM, OPT_OPENCL_DEVICE, _T("--device"), 0, SO_REQ_SEP, "\t--device The OpenCL device index within the specified platform to use [default: 0].\n"));
|
||||
INITUINTOPTION(Seed, Eou(OPT_USE_ALL, OPT_SEED, _T("--seed"), 0, SO_REQ_SEP, "\t--seed=<val> Integer seed to use for the random number generator [default: random].\n"));
|
||||
INITUINTOPTION(ThreadCount, Eou(OPT_USE_ALL, OPT_NTHREADS, _T("--nthreads"), 0, SO_REQ_SEP, "\t--nthreads=<val> The number of threads to use [default: use all available cores].\n"));
|
||||
INITUINTOPTION(Strips, Eou(OPT_USE_RENDER, OPT_STRIPS, _T("--nstrips"), 1, SO_REQ_SEP, "\t--nstrips=<val> The number of fractions to split a single render frame into. Useful for print size renders or low memory systems [default: 1].\n"));
|
||||
INITUINTOPTION(BitsPerChannel, Eou(OPT_RENDER_ANIM, OPT_BPC, _T("--bpc"), 8, SO_REQ_SEP, "\t--bpc=<val> Bits per channel. 8 or 16 for PNG, 8 for all others [default: 8].\n"));
|
||||
INITUINTOPTION(SubBatchSize, Eou(OPT_USE_ALL, OPT_SBS, _T("--sub_batch_size"), 10000, SO_REQ_SEP, "\t--sub_batch_size=<val> The chunk size that iterating will be broken into [default: 10000].\n"));
|
||||
INITUINTOPTION(Bits, Eou(OPT_USE_ALL, OPT_BITS, _T("--bits"), 33, SO_REQ_SEP, "\t--bits=<val> Determines the types used for the histogram and accumulator [default: 33].\n"
|
||||
"\t\t\t\t\t32: Histogram: float, Accumulator: float.\n"
|
||||
"\t\t\t\t\t33: Histogram: float, Accumulator: float.\n"//This differs from the original which used an int hist for bits 33.
|
||||
"\t\t\t\t\t64: Histogram: double, Accumulator: double.\n"));
|
||||
|
||||
INITUINTOPTION(PrintEditDepth, Eou(OPT_USE_ALL, OPT_PRINT_EDIT_DEPTH, _T("--print_edit_depth"), 0, SO_REQ_SEP, "\t--print_edit_depth=<val> Depth to truncate <edit> tag structure when converting a flame to xml. 0 prints all <edit> tags [default: 0].\n"));
|
||||
INITUINTOPTION(JpegQuality, Eou(OPT_USE_ALL, OPT_JPEG, _T("--jpeg"), 95, SO_REQ_SEP, "\t--jpeg=<val> Jpeg quality 0-100 for compression [default: 95].\n"));
|
||||
INITUINTOPTION(FirstFrame, Eou(OPT_USE_ANIMATE, OPT_BEGIN, _T("--begin"), UINT_MAX, SO_REQ_SEP, "\t--begin=<val> Time of first frame to render [default: first time specified in file].\n"));
|
||||
INITUINTOPTION(LastFrame, Eou(OPT_USE_ANIMATE, OPT_END, _T("--end"), UINT_MAX, SO_REQ_SEP, "\t--end=<val> Time of last frame to render [default: last time specified in the input file].\n"));
|
||||
INITUINTOPTION(Time, Eou(OPT_ANIM_GENOME, OPT_TIME, _T("--time"), 0, SO_REQ_SEP, "\t--time=<val> Time of first and last frame (ie do one frame).\n"));
|
||||
INITUINTOPTION(Frame, Eou(OPT_ANIM_GENOME, OPT_FRAME, _T("--frame"), 0, SO_REQ_SEP, "\t--frame=<val> Synonym for \"time\".\n"));
|
||||
INITUINTOPTION(Dtime, Eou(OPT_USE_ANIMATE, OPT_DTIME, _T("--dtime"), 1, SO_REQ_SEP, "\t--dtime=<val> Time between frames [default: 1].\n"));
|
||||
INITUINTOPTION(Frames, Eou(OPT_USE_GENOME, OPT_NFRAMES, _T("--nframes"), 20, SO_REQ_SEP, "\t--nframes=<val> Number of frames for each stage of the animation [default: 20].\n"));
|
||||
INITUINTOPTION(Loops, Eou(OPT_USE_GENOME, OPT_LOOPS, _T("--loops"), 1, SO_REQ_SEP, "\t--loops=<val> Number of times to rotate each control point in sequence [default: 1].\n"));
|
||||
INITUINTOPTION(Repeat, Eou(OPT_USE_GENOME, OPT_REPEAT, _T("--repeat"), 1, SO_REQ_SEP, "\t--repeat=<val> Number of new flames to create. Ignored if sequence, inter or rotate were specified [default: 1].\n"));
|
||||
INITUINTOPTION(Tries, Eou(OPT_USE_GENOME, OPT_TRIES, _T("--tries"), 10, SO_REQ_SEP, "\t--tries=<val> Number times to try creating a flame that meets the specified constraints. Ignored if sequence, inter or rotate were specified [default: 10].\n"));
|
||||
INITUINTOPTION(MaxXforms, Eou(OPT_USE_GENOME, OPT_MAX_XFORMS, _T("--maxxforms"), UINT_MAX, SO_REQ_SEP, "\t--maxxforms=<val> The maximum number of xforms allowed in the final output.\n"));
|
||||
|
||||
//Double.
|
||||
INITDOUBLEOPTION(SizeScale, Eod(OPT_USE_ALL, OPT_SS, _T("--ss"), 1, SO_REQ_SEP, "\t--ss=<val> Size scale. All dimensions are scaled by this amount [default: 1.0].\n"));
|
||||
INITDOUBLEOPTION(QualityScale, Eod(OPT_USE_ALL, OPT_QS, _T("--qs"), 1, SO_REQ_SEP, "\t--qs=<val> Quality scale. All quality values are scaled by this amount [default: 1.0].\n"));
|
||||
INITDOUBLEOPTION(AspectRatio, Eod(OPT_USE_ALL, OPT_PIXEL_ASPECT, _T("--pixel_aspect"), 1, SO_REQ_SEP, "\t--pixel_aspect=<val> Aspect ratio of pixels (width over height), eg. 0.90909 for NTSC [default: 1.0].\n"));
|
||||
INITDOUBLEOPTION(Stagger, Eod(OPT_USE_ALL, OPT_STAGGER, _T("--stagger"), 0, SO_REQ_SEP, "\t--stagger=<val> Affects simultaneity of xform interpolation during flame interpolation.\n"
|
||||
"\t Represents how 'separate' the xforms are interpolated. Set to 1 for each\n"
|
||||
"\t xform to be interpolated individually, fractions control interpolation overlap [default: 0].\n"));
|
||||
INITDOUBLEOPTION(AvgThresh, Eod(OPT_USE_GENOME, OPT_AVG_THRESH, _T("--avg"), 20.0, SO_REQ_SEP, "\t--avg=<val> Minimum average pixel channel sum (r + g + b) threshold from 0 - 765. Ignored if sequence, inter or rotate were specified [default: 20].\n"));
|
||||
INITDOUBLEOPTION(BlackThresh, Eod(OPT_USE_GENOME, OPT_BLACK_THRESH, _T("--black"), 0.01, SO_REQ_SEP, "\t--black=<val> Minimum number of allowed black pixels as a percentage from 0 - 1. Ignored if sequence, inter or rotate were specified [default: 0.01].\n"));
|
||||
INITDOUBLEOPTION(WhiteLimit, Eod(OPT_USE_GENOME, OPT_WHITE_LIMIT, _T("--white"), 0.05, SO_REQ_SEP, "\t--white=<val> Maximum number of allowed white pixels as a percentage from 0 - 1. Ignored if sequence, inter or rotate were specified [default: 0.05].\n"));
|
||||
INITDOUBLEOPTION(Speed, Eod(OPT_USE_GENOME, OPT_SPEED, _T("--speed"), 0.1, SO_REQ_SEP, "\t--speed=<val> Speed as a percentage from 0 - 1 that the affine transform of an existing flame mutates with the new flame. Ignored if sequence, inter or rotate were specified [default: 0.1].\n"));
|
||||
INITDOUBLEOPTION(OffsetX, Eod(OPT_USE_GENOME, OPT_OFFSETX, _T("--offsetx"), 0.0, SO_REQ_SEP, "\t--offsetx=<val> Amount to jitter each flame horizontally when applying genome tools [default: 0].\n"));
|
||||
INITDOUBLEOPTION(OffsetY, Eod(OPT_USE_GENOME, OPT_OFFSETY, _T("--offsety"), 0.0, SO_REQ_SEP, "\t--offsety=<val> Amount to jitter each flame vertically when applying genome tools [default: 0].\n"));
|
||||
INITDOUBLEOPTION(UseMem, Eod(OPT_USE_RENDER, OPT_USEMEM, _T("--use_mem"), 0.0, SO_REQ_SEP, "\t--use_mem=<val> Number of bytes of memory to use [default: max system memory].\n"));
|
||||
|
||||
//String.
|
||||
INITSTRINGOPTION(IsaacSeed, Eos(OPT_USE_ALL, OPT_ISAAC_SEED, _T("--isaac_seed"), "", SO_REQ_SEP, "\t--isaac_seed=<val> Character-based seed for the random number generator [default: random].\n"));
|
||||
INITSTRINGOPTION(Input, Eos(OPT_USE_ALL, OPT_IN, _T("--in"), "", SO_REQ_SEP, "\t--in=<val> Name of the input file.\n"));
|
||||
INITSTRINGOPTION(Out, Eos(OPT_USE_ALL, OPT_OUT, _T("--out"), "", SO_REQ_SEP, "\t--out=<val> Name of a single output file. Not recommended when rendering more than one image.\n"));
|
||||
INITSTRINGOPTION(Prefix, Eos(OPT_USE_ALL, OPT_PREFIX, _T("--prefix"), "", SO_REQ_SEP, "\t--prefix=<val> Prefix to prepend to all output files.\n"));
|
||||
INITSTRINGOPTION(Suffix, Eos(OPT_USE_ALL, OPT_SUFFIX, _T("--suffix"), "", SO_REQ_SEP, "\t--suffix=<val> Suffix to append to all output files.\n"));
|
||||
INITSTRINGOPTION(Format, Eos(OPT_RENDER_ANIM, OPT_FORMAT, _T("--format"), "png", SO_REQ_SEP, "\t--format=<val> Format of the output file. Valid values are: bmp, jpg, png, ppm [default: jpg].\n"));
|
||||
INITSTRINGOPTION(PalettePath, Eos(OPT_USE_ALL, OPT_PALETTE_FILE, _T("--flam3_palettes"), "flam3-palettes.xml", SO_REQ_SEP, "\t--flam3_palettes=<val> Path and name of the palette file [default: flam3-palettes.xml].\n"));
|
||||
INITSTRINGOPTION(PaletteImage, Eos(OPT_USE_ALL, OPT_PALETTE_IMAGE, _T("--image"), "", SO_REQ_SEP, "\t--image=<val> Replace palette with png, jpg, or ppm image.\n"));
|
||||
INITSTRINGOPTION(Id, Eos(OPT_USE_ALL, OPT_ID, _T("--id"), "", SO_REQ_SEP, "\t--id=<val> ID to use in <edit> tags.\n"));
|
||||
INITSTRINGOPTION(Url, Eos(OPT_USE_ALL, OPT_URL, _T("--url"), "", SO_REQ_SEP, "\t--url=<val> URL to use in <edit> tags / img comments.\n"));
|
||||
INITSTRINGOPTION(Nick, Eos(OPT_USE_ALL, OPT_NICK, _T("--nick"), "", SO_REQ_SEP, "\t--nick=<val> Nickname to use in <edit> tags / img comments.\n"));
|
||||
INITSTRINGOPTION(Comment, Eos(OPT_USE_GENOME, OPT_COMMENT, _T("--comment"), "", SO_REQ_SEP, "\t--comment=<val> Comment to use in <edit> tags.\n"));
|
||||
|
||||
INITSTRINGOPTION(TemplateFile, Eos(OPT_USE_GENOME, OPT_TEMPLATE, _T("--template"), "", SO_REQ_SEP, "\t--template=<val> Apply defaults based on this flame.\n"));
|
||||
INITSTRINGOPTION(Clone, Eos(OPT_USE_GENOME, OPT_CLONE, _T("--clone"), "", SO_REQ_SEP, "\t--clone=<val> Clone random flame in input.\n"));
|
||||
INITSTRINGOPTION(CloneAll, Eos(OPT_USE_GENOME, OPT_CLONE_ALL, _T("--clone_all"), "", SO_REQ_SEP, "\t--clone_all=<val> Clones all flames in the input file. Useful for applying template to all flames.\n"));
|
||||
INITSTRINGOPTION(CloneAction, Eos(OPT_USE_GENOME, OPT_CLONE_ACTION, _T("--clone_action"), "", SO_REQ_SEP, "\t--clone_action=<val> A description of the clone action taking place.\n"));
|
||||
INITSTRINGOPTION(Animate, Eos(OPT_USE_GENOME, OPT_ANIMATE, _T("--animate"), "", SO_REQ_SEP, "\t--animate=<val> Interpolates between all flames in the input file, using times specified in file.\n"));
|
||||
INITSTRINGOPTION(Mutate, Eos(OPT_USE_GENOME, OPT_MUTATE, _T("--mutate"), "", SO_REQ_SEP, "\t--mutate=<val> Randomly mutate a random flame from the input file.\n"));
|
||||
INITSTRINGOPTION(Cross0, Eos(OPT_USE_GENOME, OPT_CROSS0, _T("--cross0"), "", SO_REQ_SEP, "\t--cross0=<val> Randomly select one flame from the input file to genetically cross...\n"));
|
||||
INITSTRINGOPTION(Cross1, Eos(OPT_USE_GENOME, OPT_CROSS1, _T("--cross1"), "", SO_REQ_SEP, "\t--cross1=<val> ...with one flame from this file.\n"));
|
||||
INITSTRINGOPTION(Method, Eos(OPT_USE_GENOME, OPT_METHOD, _T("--method"), "", SO_REQ_SEP, "\t--method=<val> Method used for genetic cross: alternate, interpolate, or union. For mutate: all_vars, one_xform, add_symmetry, post_xforms, color_palette, delete_xform, all_coefs [default: random].\n"));//Original ommitted this important documentation for mutate!
|
||||
INITSTRINGOPTION(Inter, Eos(OPT_USE_GENOME, OPT_INTER, _T("--inter"), "", SO_REQ_SEP, "\t--inter=<val> Interpolate the input file.\n"));
|
||||
INITSTRINGOPTION(Rotate, Eos(OPT_USE_GENOME, OPT_ROTATE, _T("--rotate"), "", SO_REQ_SEP, "\t--rotate=<val> Rotate the input file.\n"));
|
||||
INITSTRINGOPTION(Strip, Eos(OPT_USE_GENOME, OPT_STRIP, _T("--strip"), "", SO_REQ_SEP, "\t--strip=<val> Break strip out of each flame in the input file.\n"));
|
||||
INITSTRINGOPTION(Sequence, Eos(OPT_USE_GENOME, OPT_SEQUENCE, _T("--sequence"), "", SO_REQ_SEP, "\t--sequence=<val> 360 degree rotation 'loops' times of each control point in the input file plus rotating transitions.\n"));
|
||||
INITSTRINGOPTION(UseVars, Eos(OPT_USE_GENOME, OPT_USE_VARS, _T("--use_vars"), "", SO_REQ_SEP, "\t--use_vars=<val> Comma separated list of variation #'s to use when generating a random flame.\n"));
|
||||
INITSTRINGOPTION(DontUseVars, Eos(OPT_USE_GENOME, OPT_DONT_USE_VARS, _T("--dont_use_vars"), "", SO_REQ_SEP, "\t--dont_use_vars=<val> Comma separated list of variation #'s to NOT use when generating a random flame.\n"));
|
||||
INITSTRINGOPTION(Extras, Eos(OPT_USE_GENOME, OPT_EXTRAS, _T("--extras"), "", SO_REQ_SEP, "\t--extras=<val> Extra attributes to place in the flame section of the Xml.\n"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse and populate the supplied command line options for the specified program usage.
|
||||
/// If --help or --version were specified, information will be printed
|
||||
/// and parsing will cease.
|
||||
/// </summary>
|
||||
/// <param name="argc">The number of command line arguments passed</param>
|
||||
/// <param name="argv">The command line arguments passed</param>
|
||||
/// <param name="optUsage">The program for which these options are to be parsed and used.</param>
|
||||
/// <returns>True if --help or --version specified, else false</returns>
|
||||
bool Populate(int argc, _TCHAR* argv[], eOptionUse optUsage)
|
||||
{
|
||||
EmberOptions options;
|
||||
vector<CSimpleOpt::SOption> sOptions = options.GetSimpleOptions();
|
||||
CSimpleOpt args(argc, argv, sOptions.data());
|
||||
|
||||
//Process args.
|
||||
while (args.Next())
|
||||
{
|
||||
ESOError errorCode = args.LastError();
|
||||
|
||||
if (errorCode == SO_SUCCESS)
|
||||
{
|
||||
switch (args.OptionId())
|
||||
{
|
||||
case OPT_HELP://Bool args.
|
||||
{
|
||||
ShowUsage(optUsage);
|
||||
return true;
|
||||
}
|
||||
case OPT_VERSION:
|
||||
{
|
||||
cout << EmberVersion() << endl;
|
||||
return true;
|
||||
}
|
||||
PARSEBOOLOPTION(OPT_VERBOSE, Verbose);
|
||||
PARSEBOOLOPTION(OPT_DEBUG, Debug);
|
||||
PARSEBOOLOPTION(OPT_DUMP_ARGS, DumpArgs);
|
||||
PARSEBOOLOPTION(OPT_PROGRESS, DoProgress);
|
||||
PARSEBOOLOPTION(OPT_DUMP_OPENCL_INFO, OpenCLInfo);
|
||||
PARSEBOOLOPTION(OPT_OPENCL, EmberCL);
|
||||
PARSEBOOLOPTION(OPT_EARLYCLIP, EarlyClip);
|
||||
PARSEBOOLOPTION(OPT_TRANSPARENCY, Transparency);
|
||||
PARSEBOOLOPTION(OPT_NAME_ENABLE, NameEnable);
|
||||
PARSEBOOLOPTION(OPT_INT_PALETTE, IntPalette);
|
||||
PARSEBOOLOPTION(OPT_HEX_PALETTE, HexPalette);
|
||||
PARSEBOOLOPTION(OPT_INSERT_PALETTE, InsertPalette);
|
||||
PARSEBOOLOPTION(OPT_JPEG_COMMENTS, JpegComments);
|
||||
PARSEBOOLOPTION(OPT_PNG_COMMENTS, PngComments);
|
||||
PARSEBOOLOPTION(OPT_WRITE_GENOME, WriteGenome);
|
||||
PARSEBOOLOPTION(OPT_ENCLOSED, Enclosed);
|
||||
PARSEBOOLOPTION(OPT_NO_EDITS, NoEdits);
|
||||
PARSEBOOLOPTION(OPT_UNSMOOTH_EDGE, UnsmoothEdge);
|
||||
PARSEBOOLOPTION(OPT_LOCK_ACCUM, LockAccum);
|
||||
PARSEBOOLOPTION(OPT_DUMP_KERNEL, DumpKernel);
|
||||
|
||||
PARSEINTOPTION(OPT_SYMMETRY, Symmetry);//Int args
|
||||
PARSEINTOPTION(OPT_SHEEP_GEN, SheepGen);
|
||||
PARSEINTOPTION(OPT_SHEEP_ID, SheepId);
|
||||
PARSEUINTOPTION(OPT_OPENCL_PLATFORM, Platform);//Unsigned int args.
|
||||
PARSEUINTOPTION(OPT_OPENCL_DEVICE, Device);
|
||||
PARSEUINTOPTION(OPT_SEED, Seed);
|
||||
PARSEUINTOPTION(OPT_NTHREADS, ThreadCount);
|
||||
PARSEUINTOPTION(OPT_STRIPS, Strips);
|
||||
PARSEUINTOPTION(OPT_BITS, Bits);
|
||||
PARSEUINTOPTION(OPT_BPC, BitsPerChannel);
|
||||
PARSEUINTOPTION(OPT_SBS, SubBatchSize);
|
||||
PARSEUINTOPTION(OPT_PRINT_EDIT_DEPTH, PrintEditDepth);
|
||||
PARSEUINTOPTION(OPT_JPEG, JpegQuality);
|
||||
PARSEUINTOPTION(OPT_BEGIN, FirstFrame);
|
||||
PARSEUINTOPTION(OPT_END, LastFrame);
|
||||
PARSEUINTOPTION(OPT_FRAME, Frame);
|
||||
PARSEUINTOPTION(OPT_TIME, Time);
|
||||
PARSEUINTOPTION(OPT_DTIME, Dtime);
|
||||
PARSEUINTOPTION(OPT_NFRAMES, Frames);
|
||||
PARSEUINTOPTION(OPT_LOOPS, Loops);
|
||||
PARSEUINTOPTION(OPT_REPEAT, Repeat);
|
||||
PARSEUINTOPTION(OPT_TRIES, Tries);
|
||||
PARSEUINTOPTION(OPT_MAX_XFORMS, MaxXforms);
|
||||
|
||||
PARSEDOUBLEOPTION(OPT_SS, SizeScale);//Float args.
|
||||
PARSEDOUBLEOPTION(OPT_QS, QualityScale);
|
||||
PARSEDOUBLEOPTION(OPT_PIXEL_ASPECT, AspectRatio);
|
||||
PARSEDOUBLEOPTION(OPT_STAGGER, Stagger);
|
||||
PARSEDOUBLEOPTION(OPT_AVG_THRESH, AvgThresh);
|
||||
PARSEDOUBLEOPTION(OPT_BLACK_THRESH, BlackThresh);
|
||||
PARSEDOUBLEOPTION(OPT_WHITE_LIMIT, WhiteLimit);
|
||||
PARSEDOUBLEOPTION(OPT_SPEED, Speed);
|
||||
PARSEDOUBLEOPTION(OPT_OFFSETX, OffsetX);
|
||||
PARSEDOUBLEOPTION(OPT_OFFSETY, OffsetY);
|
||||
PARSEDOUBLEOPTION(OPT_USEMEM, UseMem);
|
||||
|
||||
PARSESTRINGOPTION(OPT_ISAAC_SEED, IsaacSeed);//String args.
|
||||
PARSESTRINGOPTION(OPT_IN, Input);
|
||||
PARSESTRINGOPTION(OPT_OUT, Out);
|
||||
PARSESTRINGOPTION(OPT_PREFIX, Prefix);
|
||||
PARSESTRINGOPTION(OPT_SUFFIX, Suffix);
|
||||
PARSESTRINGOPTION(OPT_FORMAT, Format);
|
||||
PARSESTRINGOPTION(OPT_PALETTE_FILE, PalettePath);
|
||||
PARSESTRINGOPTION(OPT_PALETTE_IMAGE, PaletteImage);
|
||||
PARSESTRINGOPTION(OPT_ID, Id);
|
||||
PARSESTRINGOPTION(OPT_URL, Url);
|
||||
PARSESTRINGOPTION(OPT_NICK, Nick);
|
||||
PARSESTRINGOPTION(OPT_COMMENT, Comment);
|
||||
PARSESTRINGOPTION(OPT_TEMPLATE, TemplateFile);
|
||||
PARSESTRINGOPTION(OPT_CLONE, Clone);
|
||||
PARSESTRINGOPTION(OPT_CLONE_ALL, CloneAll);
|
||||
PARSESTRINGOPTION(OPT_CLONE_ACTION, CloneAction);
|
||||
PARSESTRINGOPTION(OPT_ANIMATE, Animate);
|
||||
PARSESTRINGOPTION(OPT_MUTATE, Mutate);
|
||||
PARSESTRINGOPTION(OPT_CROSS0, Cross0);
|
||||
PARSESTRINGOPTION(OPT_CROSS1, Cross1);
|
||||
PARSESTRINGOPTION(OPT_METHOD, Method);
|
||||
PARSESTRINGOPTION(OPT_INTER, Inter);
|
||||
PARSESTRINGOPTION(OPT_ROTATE, Rotate);
|
||||
PARSESTRINGOPTION(OPT_STRIP, Strip);
|
||||
PARSESTRINGOPTION(OPT_SEQUENCE, Sequence);
|
||||
PARSESTRINGOPTION(OPT_USE_VARS, UseVars);
|
||||
PARSESTRINGOPTION(OPT_DONT_USE_VARS, DontUseVars);
|
||||
PARSESTRINGOPTION(OPT_EXTRAS, Extras);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Invalid argument: " << args.OptionText() << endl;
|
||||
cout << "\tReason: " << GetLastErrorText(errorCode) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a vector of all available options for the specified program.
|
||||
/// </summary>
|
||||
/// <param name="optUsage">The specified program usage</param>
|
||||
/// <returns>A vector of all available options for the specified program</returns>
|
||||
vector<CSimpleOpt::SOption> GetSimpleOptions(eOptionUse optUsage = OPT_USE_ALL)
|
||||
{
|
||||
vector<CSimpleOpt::SOption> entries;
|
||||
CSimpleOpt::SOption endOption = SO_END_OF_OPTIONS;
|
||||
entries.reserve(75);
|
||||
|
||||
std::for_each(m_BoolArgs.begin(), m_BoolArgs.end(), [&](Eob* entry) { if (entry->m_OptionUse & optUsage) entries.push_back(entry->m_Option); });
|
||||
std::for_each(m_IntArgs.begin(), m_IntArgs.end(), [&](Eoi* entry) { if (entry->m_OptionUse & optUsage) entries.push_back(entry->m_Option); });
|
||||
std::for_each(m_UintArgs.begin(), m_UintArgs.end(), [&](Eou* entry) { if (entry->m_OptionUse & optUsage) entries.push_back(entry->m_Option); });
|
||||
std::for_each(m_DoubleArgs.begin(), m_DoubleArgs.end(), [&](Eod* entry) { if (entry->m_OptionUse & optUsage) entries.push_back(entry->m_Option); });
|
||||
std::for_each(m_StringArgs.begin(), m_StringArgs.end(), [&](Eos* entry) { if (entry->m_OptionUse & optUsage) entries.push_back(entry->m_Option); });
|
||||
|
||||
entries.push_back(endOption);
|
||||
return entries;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string with the descriptions of all available options for the specified program.
|
||||
/// </summary>
|
||||
/// <param name="optUsage">The specified program usage</param>
|
||||
/// <returns>A string with the descriptions of all available options for the specified program</returns>
|
||||
string GetUsage(eOptionUse optUsage = OPT_USE_ALL)
|
||||
{
|
||||
ostringstream os;
|
||||
|
||||
std::for_each(m_BoolArgs.begin(), m_BoolArgs.end(), [&](Eob* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_DocString << endl; });
|
||||
std::for_each(m_IntArgs.begin(), m_IntArgs.end(), [&](Eoi* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_DocString << endl; });
|
||||
std::for_each(m_UintArgs.begin(), m_UintArgs.end(), [&](Eou* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_DocString << endl; });
|
||||
std::for_each(m_DoubleArgs.begin(), m_DoubleArgs.end(), [&](Eod* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_DocString << endl; });
|
||||
std::for_each(m_StringArgs.begin(), m_StringArgs.end(), [&](Eos* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_DocString << endl; });
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string with all of the names and values for all available options for the specified program.
|
||||
/// </summary>
|
||||
/// <param name="optUsage">The specified program usage</param>
|
||||
/// <returns>A string with all of the names and values for all available options for the specified program</returns>
|
||||
string GetValues(eOptionUse optUsage = OPT_USE_ALL)
|
||||
{
|
||||
ostringstream os;
|
||||
|
||||
os << std::boolalpha;
|
||||
std::for_each(m_BoolArgs.begin(), m_BoolArgs.end(), [&](Eob* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_NameWithoutDashes << ": " << (*entry)() << endl; });
|
||||
std::for_each(m_IntArgs.begin(), m_IntArgs.end(), [&](Eoi* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_NameWithoutDashes << ": " << (*entry)() << endl; });
|
||||
std::for_each(m_UintArgs.begin(), m_UintArgs.end(), [&](Eou* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_NameWithoutDashes << ": " << (*entry)() << endl; });
|
||||
std::for_each(m_DoubleArgs.begin(), m_DoubleArgs.end(), [&](Eod* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_NameWithoutDashes << ": " << (*entry)() << endl; });
|
||||
std::for_each(m_StringArgs.begin(), m_StringArgs.end(), [&](Eos* entry) { if (entry->m_OptionUse & optUsage) os << entry->m_NameWithoutDashes << ": " << (*entry)() << endl; });
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print description string, version and description of all available options for the specified program.
|
||||
/// </summary>
|
||||
/// <param name="optUsage">The specified program usage</param>
|
||||
void ShowUsage(eOptionUse optUsage)
|
||||
{
|
||||
cout << DescriptionString << " version " << EmberVersion() << endl << endl;
|
||||
|
||||
if (optUsage == OPT_USE_RENDER)
|
||||
{
|
||||
cout << "Usage:\n"
|
||||
"\tEmberRender.exe --in=test.flam3 [--out=outfile --format=png --verbose --progress --opencl]\n" << endl;
|
||||
}
|
||||
else if (optUsage == OPT_USE_ANIMATE)
|
||||
{
|
||||
cout << "Usage:\n"
|
||||
"\tEmberAnimate.exe --in=sequence.flam3 [--format=png --verbose --progress --opencl]\n" << endl;
|
||||
}
|
||||
else if (optUsage == OPT_USE_GENOME)
|
||||
{
|
||||
cout << "Usage:\n"
|
||||
"\tEmberGenome.exe --sequence=test.flam3 > sequenceout.flam3\n" << endl;
|
||||
}
|
||||
|
||||
cout << GetUsage(optUsage) << endl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the last option parsing error text as a string.
|
||||
/// </summary>
|
||||
/// <param name="errorCode">The code of the last parsing error</param>
|
||||
/// <returns>The last option parsing error text as a string</returns>
|
||||
string GetLastErrorText(int errorCode)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case SO_SUCCESS: return "Success";
|
||||
case SO_OPT_INVALID: return "Unrecognized option";
|
||||
case SO_OPT_MULTIPLE: return "Option matched multiple strings";
|
||||
case SO_ARG_INVALID: return "Option does not accept argument";
|
||||
case SO_ARG_INVALID_TYPE: return "Invalid argument format";
|
||||
case SO_ARG_MISSING: return "Required argument is missing";
|
||||
case SO_ARG_INVALID_DATA: return "Invalid argument data";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
//Break from the usual m_* notation for members here because
|
||||
//each of these is a functor, so it looks nicer and is less typing
|
||||
//to just say opt.Member().
|
||||
EmberOptionEntry<bool> Help;//Diagnostic bool.
|
||||
EmberOptionEntry<bool> Version;
|
||||
EmberOptionEntry<bool> Verbose;
|
||||
EmberOptionEntry<bool> Debug;
|
||||
EmberOptionEntry<bool> DumpArgs;
|
||||
EmberOptionEntry<bool> DoProgress;
|
||||
EmberOptionEntry<bool> OpenCLInfo;
|
||||
|
||||
EmberOptionEntry<bool> EmberCL;//Value bool.
|
||||
EmberOptionEntry<bool> EarlyClip;
|
||||
EmberOptionEntry<bool> Transparency;
|
||||
EmberOptionEntry<bool> NameEnable;
|
||||
EmberOptionEntry<bool> IntPalette;
|
||||
EmberOptionEntry<bool> HexPalette;
|
||||
EmberOptionEntry<bool> InsertPalette;
|
||||
EmberOptionEntry<bool> JpegComments;
|
||||
EmberOptionEntry<bool> PngComments;
|
||||
EmberOptionEntry<bool> WriteGenome;
|
||||
EmberOptionEntry<bool> Enclosed;
|
||||
EmberOptionEntry<bool> NoEdits;
|
||||
EmberOptionEntry<bool> UnsmoothEdge;
|
||||
EmberOptionEntry<bool> LockAccum;
|
||||
EmberOptionEntry<bool> DumpKernel;
|
||||
|
||||
EmberOptionEntry<int> Symmetry;//Value int.
|
||||
EmberOptionEntry<int> SheepGen;//Value int.
|
||||
EmberOptionEntry<int> SheepId;//Value int.
|
||||
EmberOptionEntry<unsigned int> Platform;//Value unsigned int.
|
||||
EmberOptionEntry<unsigned int> Device;
|
||||
EmberOptionEntry<unsigned int> Seed;
|
||||
EmberOptionEntry<unsigned int> ThreadCount;
|
||||
EmberOptionEntry<unsigned int> Strips;
|
||||
EmberOptionEntry<unsigned int> BitsPerChannel;
|
||||
EmberOptionEntry<unsigned int> SubBatchSize;
|
||||
EmberOptionEntry<unsigned int> Bits;
|
||||
EmberOptionEntry<unsigned int> PrintEditDepth;
|
||||
EmberOptionEntry<unsigned int> JpegQuality;
|
||||
EmberOptionEntry<unsigned int> FirstFrame;
|
||||
EmberOptionEntry<unsigned int> LastFrame;
|
||||
EmberOptionEntry<unsigned int> Frame;
|
||||
EmberOptionEntry<unsigned int> Time;
|
||||
EmberOptionEntry<unsigned int> Dtime;
|
||||
EmberOptionEntry<unsigned int> Frames;
|
||||
EmberOptionEntry<unsigned int> Loops;
|
||||
EmberOptionEntry<unsigned int> Repeat;
|
||||
EmberOptionEntry<unsigned int> Tries;
|
||||
EmberOptionEntry<unsigned int> MaxXforms;
|
||||
|
||||
EmberOptionEntry<double> SizeScale;//Value double.
|
||||
EmberOptionEntry<double> QualityScale;
|
||||
EmberOptionEntry<double> AspectRatio;
|
||||
EmberOptionEntry<double> Stagger;
|
||||
EmberOptionEntry<double> AvgThresh;
|
||||
EmberOptionEntry<double> BlackThresh;
|
||||
EmberOptionEntry<double> WhiteLimit;
|
||||
EmberOptionEntry<double> Speed;
|
||||
EmberOptionEntry<double> OffsetX;
|
||||
EmberOptionEntry<double> OffsetY;
|
||||
EmberOptionEntry<double> UseMem;
|
||||
|
||||
EmberOptionEntry<string> IsaacSeed;//Value string.
|
||||
EmberOptionEntry<string> Input;
|
||||
EmberOptionEntry<string> Out;
|
||||
EmberOptionEntry<string> Prefix;
|
||||
EmberOptionEntry<string> Suffix;
|
||||
EmberOptionEntry<string> Format;
|
||||
EmberOptionEntry<string> PalettePath;
|
||||
EmberOptionEntry<string> PaletteImage;
|
||||
EmberOptionEntry<string> Id;
|
||||
EmberOptionEntry<string> Url;
|
||||
EmberOptionEntry<string> Nick;
|
||||
EmberOptionEntry<string> Comment;
|
||||
EmberOptionEntry<string> TemplateFile;
|
||||
EmberOptionEntry<string> Clone;
|
||||
EmberOptionEntry<string> CloneAll;
|
||||
EmberOptionEntry<string> CloneAction;
|
||||
EmberOptionEntry<string> Animate;
|
||||
EmberOptionEntry<string> Mutate;
|
||||
EmberOptionEntry<string> Cross0;
|
||||
EmberOptionEntry<string> Cross1;
|
||||
EmberOptionEntry<string> Method;
|
||||
EmberOptionEntry<string> Inter;
|
||||
EmberOptionEntry<string> Rotate;
|
||||
EmberOptionEntry<string> Strip;
|
||||
EmberOptionEntry<string> Sequence;
|
||||
EmberOptionEntry<string> UseVars;
|
||||
EmberOptionEntry<string> DontUseVars;
|
||||
EmberOptionEntry<string> Extras;
|
||||
|
||||
private:
|
||||
vector<EmberOptionEntry<bool>*> m_BoolArgs;
|
||||
vector<EmberOptionEntry<int>*> m_IntArgs;
|
||||
vector<EmberOptionEntry<unsigned int>*> m_UintArgs;
|
||||
vector<EmberOptionEntry<double>*> m_DoubleArgs;
|
||||
vector<EmberOptionEntry<string>*> m_StringArgs;
|
||||
};
|
362
Source/EmberCommon/JpegUtils.h
Normal file
362
Source/EmberCommon/JpegUtils.h
Normal file
@ -0,0 +1,362 @@
|
||||
#pragma once
|
||||
|
||||
#include "EmberCommonPch.h"
|
||||
|
||||
#define PNG_COMMENT_MAX 8
|
||||
|
||||
/// <summary>
|
||||
/// Write a PPM file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="image">Pointer to the image data to write</param>
|
||||
/// <param name="width">Width of the image in pixels</param>
|
||||
/// <param name="height">Height of the image in pixels</param>
|
||||
/// <returns>True if success, else false</returns>
|
||||
static bool WritePpm(const char* filename, unsigned char* image, int width, int height)
|
||||
{
|
||||
bool b = false;
|
||||
unsigned int size = width * height * 3;
|
||||
FILE* file;
|
||||
|
||||
if (fopen_s(&file, filename, "wb") == 0)
|
||||
{
|
||||
fprintf_s(file, "P6\n");
|
||||
fprintf_s(file, "%d %d\n255\n", width, height);
|
||||
|
||||
b = (size == fwrite(image, 1, size, file));
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a JPEG file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="image">Pointer to the image data to write</param>
|
||||
/// <param name="width">Width of the image in pixels</param>
|
||||
/// <param name="height">Height of the image in pixels</param>
|
||||
/// <param name="quality">The quality to use</param>
|
||||
/// <param name="enableComments">True to embed comments, else false</param>
|
||||
/// <param name="comments">The comment string to embed</param>
|
||||
/// <param name="id">Id of the author</param>
|
||||
/// <param name="url">Url of the author</param>
|
||||
/// <param name="nick">Nickname of the author</param>
|
||||
/// <returns>True if success, else false</returns>
|
||||
static bool WriteJpeg(const char* filename, unsigned char* image, unsigned int width, unsigned int height, int quality, bool enableComments, EmberImageComments& comments, string id, string url, string nick)
|
||||
{
|
||||
bool b = false;
|
||||
FILE* file;
|
||||
|
||||
if (fopen_s(&file, filename, "wb") == 0)
|
||||
{
|
||||
size_t i;
|
||||
jpeg_error_mgr jerr;
|
||||
jpeg_compress_struct info;
|
||||
char nickString[64], urlString[128], idString[128];
|
||||
char bvString[64], niString[64], rtString[64];
|
||||
char genomeString[65536], verString[64];
|
||||
|
||||
//Create the mandatory comment strings.
|
||||
snprintf_s(genomeString, 65536, "flam3_genome: %s", comments.m_Genome.c_str());
|
||||
snprintf_s(bvString, 64, "flam3_error_rate: %s", comments.m_Badvals.c_str());
|
||||
snprintf_s(niString, 64, "flam3_samples: %s", comments.m_NumIters);
|
||||
snprintf_s(rtString, 64, "flam3_time: %s", comments.m_Runtime.c_str());
|
||||
snprintf_s(verString, 64, "flam3_version: %s", EmberVersion());
|
||||
|
||||
info.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&info);
|
||||
jpeg_stdio_dest(&info, file);
|
||||
info.in_color_space = JCS_RGB;
|
||||
info.input_components = 3;
|
||||
info.image_width = width;
|
||||
info.image_height = height;
|
||||
jpeg_set_defaults(&info);
|
||||
jpeg_set_quality(&info, quality, TRUE);
|
||||
jpeg_start_compress(&info, TRUE);
|
||||
|
||||
//Write comments to jpeg.
|
||||
if (enableComments)
|
||||
{
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)verString, (int)strlen(verString));
|
||||
|
||||
if (nick != "")
|
||||
{
|
||||
snprintf_s(nickString, 64, "flam3_nickname: %s", nick.c_str());
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)nickString, (int)strlen(nickString));
|
||||
}
|
||||
|
||||
if (url != "")
|
||||
{
|
||||
snprintf_s(urlString, 128, "flam3_url: %s", url.c_str());
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)urlString, (int)strlen(urlString));
|
||||
}
|
||||
|
||||
if (id != "")
|
||||
{
|
||||
snprintf_s(idString, 128, "flam3_id: %s", id.c_str());
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)idString, (int)strlen(idString));
|
||||
}
|
||||
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)bvString, (int)strlen(bvString));
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)niString, (int)strlen(niString));
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)rtString, (int)strlen(rtString));
|
||||
jpeg_write_marker(&info, JPEG_COM, (unsigned char*)genomeString, (int)strlen(genomeString));
|
||||
}
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
JSAMPROW row_pointer[1];
|
||||
row_pointer[0] = (unsigned char*)image + (3 * width * i);
|
||||
jpeg_write_scanlines(&info, row_pointer, 1);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&info);
|
||||
jpeg_destroy_compress(&info);
|
||||
fclose(file);
|
||||
b = true;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a PNG file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="image">Pointer to the image data to write</param>
|
||||
/// <param name="width">Width of the image in pixels</param>
|
||||
/// <param name="height">Height of the image in pixels</param>
|
||||
/// <param name="bytesPerChannel">Bytes per channel, 1 or 2.</param>
|
||||
/// <param name="enableComments">True to embed comments, else false</param>
|
||||
/// <param name="comments">The comment string to embed</param>
|
||||
/// <param name="id">Id of the author</param>
|
||||
/// <param name="url">Url of the author</param>
|
||||
/// <param name="nick">Nickname of the author</param>
|
||||
/// <returns>True if success, else false</returns>
|
||||
static bool WritePng(const char* filename, unsigned char* image, unsigned int width, unsigned int height, int bytesPerChannel, bool enableComments, EmberImageComments& comments, string id, string url, string nick)
|
||||
{
|
||||
bool b = false;
|
||||
FILE* file;
|
||||
|
||||
if (fopen_s(&file, filename, "wb") == 0)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_text text[PNG_COMMENT_MAX];
|
||||
size_t i;
|
||||
unsigned short testbe = 1;
|
||||
vector<unsigned char*> rows(height);
|
||||
|
||||
text[0].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[0].key = "flam3_version";
|
||||
text[0].text = EmberVersion();
|
||||
|
||||
text[1].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[1].key = "flam3_nickname";
|
||||
text[1].text = (png_charp)nick.c_str();
|
||||
|
||||
text[2].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[2].key = "flam3_url";
|
||||
text[2].text = (png_charp)url.c_str();
|
||||
|
||||
text[3].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[3].key = "flam3_id";
|
||||
text[3].text = (png_charp)id.c_str();
|
||||
|
||||
text[4].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[4].key = "flam3_error_rate";
|
||||
text[4].text = (png_charp)comments.m_Badvals.c_str();
|
||||
|
||||
text[5].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[5].key = "flam3_samples";
|
||||
text[5].text = (png_charp)comments.m_NumIters.c_str();
|
||||
|
||||
text[6].compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
text[6].key = "flam3_time";
|
||||
text[6].text = (png_charp)comments.m_Runtime.c_str();
|
||||
|
||||
text[7].compression = PNG_TEXT_COMPRESSION_zTXt;
|
||||
text[7].key = "flam3_genome";
|
||||
text[7].text = (png_charp)comments.m_Genome.c_str();
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
rows[i] = (unsigned char*)image + i * width * 4 * bytesPerChannel;
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
fclose(file);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
perror("writing file");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, file);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, width, height, 8 * bytesPerChannel,
|
||||
PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_BASE,
|
||||
PNG_FILTER_TYPE_BASE);
|
||||
|
||||
if (enableComments == 1)
|
||||
png_set_text(png_ptr, info_ptr, text, PNG_COMMENT_MAX);
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
//Must set this after png_write_info().
|
||||
if (bytesPerChannel == 2 && testbe != htons(testbe))
|
||||
{
|
||||
png_set_swap(png_ptr);
|
||||
}
|
||||
|
||||
png_write_image(png_ptr, (png_bytepp) rows.data());
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(file);
|
||||
b = true;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an RGB buffer to BGR for usage with BMP.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to convert</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
/// <param name="newSize">The size of the new buffer created</param>
|
||||
/// <returns>The converted buffer if successful, else NULL.</returns>
|
||||
static BYTE* ConvertRGBToBMPBuffer(BYTE* buffer, int width, int height, long& newSize)
|
||||
{
|
||||
if (NULL == buffer || width == 0 || height == 0)
|
||||
return NULL;
|
||||
|
||||
int padding = 0;
|
||||
int scanlinebytes = width * 3;
|
||||
while ((scanlinebytes + padding ) % 4 != 0)
|
||||
padding++;
|
||||
|
||||
int psw = scanlinebytes + padding;
|
||||
|
||||
newSize = height * psw;
|
||||
BYTE* newBuf = new BYTE[newSize];
|
||||
|
||||
if (newBuf)
|
||||
{
|
||||
memset (newBuf, 0, newSize);
|
||||
|
||||
long bufpos = 0;
|
||||
long newpos = 0;
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < 3 * width; x += 3)
|
||||
{
|
||||
bufpos = y * 3 * width + x; // position in original buffer
|
||||
newpos = (height - y - 1) * psw + x; // position in padded buffer
|
||||
newBuf[newpos] = buffer[bufpos+2]; // swap r and b
|
||||
newBuf[newpos + 1] = buffer[bufpos + 1]; // g stays
|
||||
newBuf[newpos + 2] = buffer[bufpos]; // swap b and r
|
||||
|
||||
//No swap.
|
||||
//newBuf[newpos] = buffer[bufpos];
|
||||
//newBuf[newpos + 1] = buffer[bufpos + 1];
|
||||
//newBuf[newpos + 2] = buffer[bufpos + 2];
|
||||
}
|
||||
}
|
||||
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save a Bmp file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="image">Pointer to the image data to write</param>
|
||||
/// <param name="width">Width of the image in pixels</param>
|
||||
/// <param name="height">Height of the image in pixels</param>
|
||||
/// <param name="paddedSize">Padded size, greater than or equal to total image size.</param>
|
||||
/// <returns>True if success, else false</returns>
|
||||
static bool SaveBmp(const char* filename, BYTE* image, int width, int height, long paddedSize)
|
||||
{
|
||||
BITMAPFILEHEADER bmfh;
|
||||
BITMAPINFOHEADER info;
|
||||
unsigned long bwritten;
|
||||
HANDLE file;
|
||||
memset (&bmfh, 0, sizeof (BITMAPFILEHEADER));
|
||||
memset (&info, 0, sizeof (BITMAPINFOHEADER));
|
||||
|
||||
bmfh.bfType = 0x4d42; // 0x4d42 = 'BM'
|
||||
bmfh.bfReserved1 = 0;
|
||||
bmfh.bfReserved2 = 0;
|
||||
bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + paddedSize;
|
||||
bmfh.bfOffBits = 0x36;
|
||||
|
||||
info.biSize = sizeof(BITMAPINFOHEADER);
|
||||
info.biWidth = width;
|
||||
info.biHeight = height;
|
||||
info.biPlanes = 1;
|
||||
info.biBitCount = 24;
|
||||
info.biCompression = BI_RGB;
|
||||
info.biSizeImage = 0;
|
||||
info.biXPelsPerMeter = 0x0ec4;
|
||||
info.biYPelsPerMeter = 0x0ec4;
|
||||
info.biClrUsed = 0;
|
||||
info.biClrImportant = 0;
|
||||
|
||||
if ((file = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == NULL)
|
||||
{
|
||||
CloseHandle(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WriteFile(file, &bmfh, sizeof (BITMAPFILEHEADER), &bwritten, NULL) == false)
|
||||
{
|
||||
CloseHandle(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WriteFile(file, &info, sizeof(BITMAPINFOHEADER), &bwritten, NULL) == false)
|
||||
{
|
||||
CloseHandle(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WriteFile(file, image, paddedSize, &bwritten, NULL) == false)
|
||||
{
|
||||
CloseHandle(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a buffer from RGB to BGR and write a Bmp file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The full path and name of the file</param>
|
||||
/// <param name="image">Pointer to the image data to write</param>
|
||||
/// <param name="width">Width of the image in pixels</param>
|
||||
/// <param name="height">Height of the image in pixels</param>
|
||||
/// <returns>True if success, else false</returns>
|
||||
static bool WriteBmp(const char* filename, unsigned char* image, int width, int height)
|
||||
{
|
||||
bool b = false;
|
||||
long newSize;
|
||||
auto_ptr<BYTE> bgrBuf(ConvertRGBToBMPBuffer(image, width, height, newSize));
|
||||
|
||||
if (bgrBuf.get())
|
||||
b = SaveBmp(filename, bgrBuf.get(), width, height, newSize);
|
||||
|
||||
return b;
|
||||
}
|
959
Source/EmberCommon/SimpleGlob.h
Normal file
959
Source/EmberCommon/SimpleGlob.h
Normal file
@ -0,0 +1,959 @@
|
||||
/*! @file SimpleGlob.h
|
||||
|
||||
@version 3.6
|
||||
|
||||
@brief A cross-platform file globbing library providing the ability to
|
||||
expand wildcards in command-line arguments to a list of all matching
|
||||
files. It is designed explicitly to be portable to any platform and has
|
||||
been tested on Windows and Linux. See CSimpleGlobTempl for the class
|
||||
definition.
|
||||
|
||||
@section features FEATURES
|
||||
- MIT Licence allows free use in all software (including GPL and
|
||||
commercial)
|
||||
- multi-platform (Windows 95/98/ME/NT/2K/XP, Linux, Unix)
|
||||
- supports most of the standard linux glob() options
|
||||
- recognition of a forward paths as equivalent to a backward slash
|
||||
on Windows. e.g. "c:/path/foo*" is equivalent to "c:\path\foo*".
|
||||
- implemented with only a single C++ header file
|
||||
- char, wchar_t and Windows TCHAR in the same program
|
||||
- complete working examples included
|
||||
- compiles cleanly at warning level 4 (Windows/VC.NET 2003),
|
||||
warning level 3 (Windows/VC6) and -Wall (Linux/gcc)
|
||||
|
||||
@section usage USAGE
|
||||
The SimpleGlob class is used by following these steps:
|
||||
<ol>
|
||||
<li> Include the SimpleGlob.h header file
|
||||
|
||||
<pre>
|
||||
\#include "SimpleGlob.h"
|
||||
</pre>
|
||||
|
||||
<li> Instantiate a CSimpleGlob object supplying the appropriate flags.
|
||||
|
||||
<pre>
|
||||
@link CSimpleGlobTempl CSimpleGlob @endlink glob(FLAGS);
|
||||
</pre>
|
||||
|
||||
<li> Add all file specifications to the glob class.
|
||||
|
||||
<pre>
|
||||
glob.Add("file*");
|
||||
glob.Add(argc, argv);
|
||||
</pre>
|
||||
|
||||
<li> Process all files with File(), Files() and FileCount()
|
||||
|
||||
<pre>
|
||||
for (int n = 0; n < glob.FileCount(); ++n) {
|
||||
ProcessFile(glob.File(n));
|
||||
}
|
||||
</pre>
|
||||
|
||||
</ol>
|
||||
|
||||
@section licence MIT LICENCE
|
||||
<pre>
|
||||
The licence text below is the boilerplate "MIT Licence" used from:
|
||||
http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
Copyright (c) 2006-2013, Brodie Thiesfield
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SimpleGlob
|
||||
#define INCLUDED_SimpleGlob
|
||||
|
||||
/*! @brief The operation of SimpleGlob is fine-tuned via the use of a
|
||||
combination of the following flags.
|
||||
|
||||
The flags may be passed at initialization of the class and used for every
|
||||
filespec added, or alternatively they may optionally be specified in the
|
||||
call to Add() and be different for each filespec.
|
||||
|
||||
@param SG_GLOB_ERR
|
||||
Return upon read error (e.g. directory does not have read permission)
|
||||
|
||||
@param SG_GLOB_MARK
|
||||
Append a slash (backslash in Windows) to every path which corresponds
|
||||
to a directory
|
||||
|
||||
@param SG_GLOB_NOSORT
|
||||
By default, files are returned in sorted into string order. With this
|
||||
flag, no sorting is done. This is not compatible with
|
||||
SG_GLOB_FULLSORT.
|
||||
|
||||
@param SG_GLOB_FULLSORT
|
||||
By default, files are sorted in groups belonging to each filespec that
|
||||
was added. For example if the filespec "b*" was added before the
|
||||
filespec "a*" then the argv array will contain all b* files sorted in
|
||||
order, followed by all a* files sorted in order. If this flag is
|
||||
specified, the entire array will be sorted ignoring the filespec
|
||||
groups.
|
||||
|
||||
@param SG_GLOB_NOCHECK
|
||||
If the pattern doesn't match anything, return the original pattern.
|
||||
|
||||
@param SG_GLOB_TILDE
|
||||
Tilde expansion is carried out (on Unix platforms)
|
||||
|
||||
@param SG_GLOB_ONLYDIR
|
||||
Return only directories which match (not compatible with
|
||||
SG_GLOB_ONLYFILE)
|
||||
|
||||
@param SG_GLOB_ONLYFILE
|
||||
Return only files which match (not compatible with SG_GLOB_ONLYDIR)
|
||||
|
||||
@param SG_GLOB_NODOT
|
||||
Do not return the "." or ".." special directories.
|
||||
*/
|
||||
enum SG_Flags {
|
||||
SG_GLOB_ERR = 1 << 0,
|
||||
SG_GLOB_MARK = 1 << 1,
|
||||
SG_GLOB_NOSORT = 1 << 2,
|
||||
SG_GLOB_NOCHECK = 1 << 3,
|
||||
SG_GLOB_TILDE = 1 << 4,
|
||||
SG_GLOB_ONLYDIR = 1 << 5,
|
||||
SG_GLOB_ONLYFILE = 1 << 6,
|
||||
SG_GLOB_NODOT = 1 << 7,
|
||||
SG_GLOB_FULLSORT = 1 << 8
|
||||
};
|
||||
|
||||
/*! @brief Error return codes */
|
||||
enum SG_Error {
|
||||
SG_SUCCESS = 0,
|
||||
SG_ERR_NOMATCH = 1,
|
||||
SG_ERR_MEMORY = -1,
|
||||
SG_ERR_FAILURE = -2
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Platform dependent implementations
|
||||
|
||||
// if we aren't on Windows and we have ICU available, then enable ICU
|
||||
// by default. Define this to 0 to intentially disable it.
|
||||
#ifndef SG_HAVE_ICU
|
||||
# if !defined(_WIN32) && defined(USTRING_H)
|
||||
# define SG_HAVE_ICU 1
|
||||
# else
|
||||
# define SG_HAVE_ICU 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// don't include this in documentation as it isn't relevant
|
||||
#ifndef DOXYGEN
|
||||
|
||||
// on Windows we want to use MBCS aware string functions and mimic the
|
||||
// Unix glob functionality. On Unix we just use glob.
|
||||
#ifdef _WIN32
|
||||
# include <mbstring.h>
|
||||
# define sg_strchr ::_mbschr
|
||||
# define sg_strrchr ::_mbsrchr
|
||||
# define sg_strlen ::_mbslen
|
||||
# if __STDC_WANT_SECURE_LIB__
|
||||
# define sg_strcpy_s(a,n,b) ::_mbscpy_s(a,n,b)
|
||||
# else
|
||||
# define sg_strcpy_s(a,n,b) ::_mbscpy(a,b)
|
||||
# endif
|
||||
# define sg_strcmp ::_mbscmp
|
||||
# define sg_strcasecmp ::_mbsicmp
|
||||
# define SOCHAR_T unsigned char
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <glob.h>
|
||||
# include <limits.h>
|
||||
# define MAX_PATH PATH_MAX
|
||||
# define sg_strchr ::strchr
|
||||
# define sg_strrchr ::strrchr
|
||||
# define sg_strlen ::strlen
|
||||
# define sg_strcpy_s(a,n,b) ::strcpy(a,b)
|
||||
# define sg_strcmp ::strcmp
|
||||
# define sg_strcasecmp ::strcasecmp
|
||||
# define SOCHAR_T char
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
// use assertions to test the input data
|
||||
#ifdef _DEBUG
|
||||
# ifdef _MSC_VER
|
||||
# include <crtdbg.h>
|
||||
# define SG_ASSERT(b) _ASSERTE(b)
|
||||
# else
|
||||
# include <assert.h>
|
||||
# define SG_ASSERT(b) assert(b)
|
||||
# endif
|
||||
#else
|
||||
# define SG_ASSERT(b)
|
||||
#endif
|
||||
|
||||
/*! @brief String manipulation functions. */
|
||||
class SimpleGlobUtil
|
||||
{
|
||||
public:
|
||||
static const char * strchr(const char *s, char c) {
|
||||
return (char *) sg_strchr((const SOCHAR_T *)s, c);
|
||||
}
|
||||
static const wchar_t * strchr(const wchar_t *s, wchar_t c) {
|
||||
return ::wcschr(s, c);
|
||||
}
|
||||
#if SG_HAVE_ICU
|
||||
static const UChar * strchr(const UChar *s, UChar c) {
|
||||
return ::u_strchr(s, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char * strrchr(const char *s, char c) {
|
||||
return (char *) sg_strrchr((const SOCHAR_T *)s, c);
|
||||
}
|
||||
static const wchar_t * strrchr(const wchar_t *s, wchar_t c) {
|
||||
return ::wcsrchr(s, c);
|
||||
}
|
||||
#if SG_HAVE_ICU
|
||||
static const UChar * strrchr(const UChar *s, UChar c) {
|
||||
return ::u_strrchr(s, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Note: char strlen returns number of bytes, not characters
|
||||
static size_t strlen(const char *s) { return ::strlen(s); }
|
||||
static size_t strlen(const wchar_t *s) { return ::wcslen(s); }
|
||||
#if SG_HAVE_ICU
|
||||
static size_t strlen(const UChar *s) { return ::u_strlen(s); }
|
||||
#endif
|
||||
|
||||
static void strcpy_s(char *dst, size_t n, const char *src) {
|
||||
(void) n;
|
||||
sg_strcpy_s((SOCHAR_T *)dst, n, (const SOCHAR_T *)src);
|
||||
}
|
||||
static void strcpy_s(wchar_t *dst, size_t n, const wchar_t *src) {
|
||||
# if __STDC_WANT_SECURE_LIB__
|
||||
::wcscpy_s(dst, n, src);
|
||||
#else
|
||||
(void) n;
|
||||
::wcscpy(dst, src);
|
||||
#endif
|
||||
}
|
||||
#if SG_HAVE_ICU
|
||||
static void strcpy_s(UChar *dst, size_t n, const UChar *src) {
|
||||
::u_strncpy(dst, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int strcmp(const char *s1, const char *s2) {
|
||||
return sg_strcmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2);
|
||||
}
|
||||
static int strcmp(const wchar_t *s1, const wchar_t *s2) {
|
||||
return ::wcscmp(s1, s2);
|
||||
}
|
||||
#if SG_HAVE_ICU
|
||||
static int strcmp(const UChar *s1, const UChar *s2) {
|
||||
return ::u_strcmp(s1, s2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int strcasecmp(const char *s1, const char *s2) {
|
||||
return sg_strcasecmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2);
|
||||
}
|
||||
#if _WIN32
|
||||
static int strcasecmp(const wchar_t *s1, const wchar_t *s2) {
|
||||
return ::_wcsicmp(s1, s2);
|
||||
}
|
||||
#endif // _WIN32
|
||||
#if SG_HAVE_ICU
|
||||
static int strcasecmp(const UChar *s1, const UChar *s2) {
|
||||
return u_strcasecmp(s1, s2, 0);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
enum SG_FileType {
|
||||
SG_FILETYPE_INVALID,
|
||||
SG_FILETYPE_FILE,
|
||||
SG_FILETYPE_DIR
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef INVALID_FILE_ATTRIBUTES
|
||||
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
#define SG_PATH_CHAR '\\'
|
||||
|
||||
/*! @brief Windows glob implementation. */
|
||||
template<class SOCHAR>
|
||||
struct SimpleGlobBase
|
||||
{
|
||||
SimpleGlobBase() : m_hFind(INVALID_HANDLE_VALUE) { }
|
||||
|
||||
int FindFirstFileS(const char * a_pszFileSpec, unsigned int) {
|
||||
m_hFind = FindFirstFileA(a_pszFileSpec, &m_oFindDataA);
|
||||
if (m_hFind != INVALID_HANDLE_VALUE) {
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
DWORD dwErr = GetLastError();
|
||||
if (dwErr == ERROR_FILE_NOT_FOUND) {
|
||||
return SG_ERR_NOMATCH;
|
||||
}
|
||||
return SG_ERR_FAILURE;
|
||||
}
|
||||
int FindFirstFileS(const wchar_t * a_pszFileSpec, unsigned int) {
|
||||
m_hFind = FindFirstFileW(a_pszFileSpec, &m_oFindDataW);
|
||||
if (m_hFind != INVALID_HANDLE_VALUE) {
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
DWORD dwErr = GetLastError();
|
||||
if (dwErr == ERROR_FILE_NOT_FOUND) {
|
||||
return SG_ERR_NOMATCH;
|
||||
}
|
||||
return SG_ERR_FAILURE;
|
||||
}
|
||||
|
||||
bool FindNextFileS(char) {
|
||||
return FindNextFileA(m_hFind, &m_oFindDataA) != FALSE;
|
||||
}
|
||||
bool FindNextFileS(wchar_t) {
|
||||
return FindNextFileW(m_hFind, &m_oFindDataW) != FALSE;
|
||||
}
|
||||
|
||||
void FindDone() {
|
||||
FindClose(m_hFind);
|
||||
}
|
||||
|
||||
const char * GetFileNameS(char) const {
|
||||
return m_oFindDataA.cFileName;
|
||||
}
|
||||
const wchar_t * GetFileNameS(wchar_t) const {
|
||||
return m_oFindDataW.cFileName;
|
||||
}
|
||||
|
||||
bool IsDirS(char) const {
|
||||
return this->GetFileTypeS(m_oFindDataA.dwFileAttributes) == SG_FILETYPE_DIR;
|
||||
}
|
||||
bool IsDirS(wchar_t) const {
|
||||
return this->GetFileTypeS(m_oFindDataW.dwFileAttributes) == SG_FILETYPE_DIR;
|
||||
}
|
||||
|
||||
SG_FileType GetFileTypeS(const char * a_pszPath) {
|
||||
return this->GetFileTypeS(GetFileAttributesA(a_pszPath));
|
||||
}
|
||||
SG_FileType GetFileTypeS(const wchar_t * a_pszPath) {
|
||||
return this->GetFileTypeS(GetFileAttributesW(a_pszPath));
|
||||
}
|
||||
SG_FileType GetFileTypeS(DWORD a_dwAttribs) const {
|
||||
if (a_dwAttribs == INVALID_FILE_ATTRIBUTES) {
|
||||
return SG_FILETYPE_INVALID;
|
||||
}
|
||||
if (a_dwAttribs & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
return SG_FILETYPE_DIR;
|
||||
}
|
||||
return SG_FILETYPE_FILE;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE m_hFind;
|
||||
WIN32_FIND_DATAA m_oFindDataA;
|
||||
WIN32_FIND_DATAW m_oFindDataW;
|
||||
};
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
#define SG_PATH_CHAR '/'
|
||||
|
||||
/*! @brief Unix glob implementation. */
|
||||
template<class SOCHAR>
|
||||
struct SimpleGlobBase
|
||||
{
|
||||
SimpleGlobBase() {
|
||||
memset(&m_glob, 0, sizeof(m_glob));
|
||||
m_uiCurr = (size_t)-1;
|
||||
}
|
||||
|
||||
~SimpleGlobBase() {
|
||||
globfree(&m_glob);
|
||||
}
|
||||
|
||||
void FilePrep() {
|
||||
m_bIsDir = false;
|
||||
size_t len = strlen(m_glob.gl_pathv[m_uiCurr]);
|
||||
if (m_glob.gl_pathv[m_uiCurr][len-1] == '/') {
|
||||
m_bIsDir = true;
|
||||
m_glob.gl_pathv[m_uiCurr][len-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int FindFirstFileS(const char * a_pszFileSpec, unsigned int a_uiFlags) {
|
||||
int nFlags = GLOB_MARK | GLOB_NOSORT;
|
||||
if (a_uiFlags & SG_GLOB_ERR) nFlags |= GLOB_ERR;
|
||||
if (a_uiFlags & SG_GLOB_TILDE) nFlags |= GLOB_TILDE;
|
||||
int rc = glob(a_pszFileSpec, nFlags, NULL, &m_glob);
|
||||
if (rc == GLOB_NOSPACE) return SG_ERR_MEMORY;
|
||||
if (rc == GLOB_ABORTED) return SG_ERR_FAILURE;
|
||||
if (rc == GLOB_NOMATCH) return SG_ERR_NOMATCH;
|
||||
m_uiCurr = 0;
|
||||
FilePrep();
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
#if SG_HAVE_ICU
|
||||
int FindFirstFileS(const UChar * a_pszFileSpec, unsigned int a_uiFlags) {
|
||||
char buf[PATH_MAX] = { 0 };
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
u_strToUTF8(buf, sizeof(buf), NULL, a_pszFileSpec, -1, &status);
|
||||
if (U_FAILURE(status)) return SG_ERR_FAILURE;
|
||||
return this->FindFirstFileS(buf, a_uiFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool FindNextFileS(char) {
|
||||
SG_ASSERT(m_uiCurr != (size_t)-1);
|
||||
if (++m_uiCurr >= m_glob.gl_pathc) {
|
||||
return false;
|
||||
}
|
||||
FilePrep();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SG_HAVE_ICU
|
||||
bool FindNextFileS(UChar) {
|
||||
return this->FindNextFileS((char)0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void FindDone() {
|
||||
globfree(&m_glob);
|
||||
memset(&m_glob, 0, sizeof(m_glob));
|
||||
m_uiCurr = (size_t)-1;
|
||||
}
|
||||
|
||||
const char * GetFileNameS(char) const {
|
||||
SG_ASSERT(m_uiCurr != (size_t)-1);
|
||||
return m_glob.gl_pathv[m_uiCurr];
|
||||
}
|
||||
|
||||
#if SG_HAVE_ICU
|
||||
const UChar * GetFileNameS(UChar) const {
|
||||
const char * pszFile = this->GetFileNameS((char)0);
|
||||
if (!pszFile) return NULL;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
memset(m_szBuf, 0, sizeof(m_szBuf));
|
||||
u_strFromUTF8(m_szBuf, PATH_MAX, NULL, pszFile, -1, &status);
|
||||
if (U_FAILURE(status)) return NULL;
|
||||
return m_szBuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsDirS(char) const {
|
||||
SG_ASSERT(m_uiCurr != (size_t)-1);
|
||||
return m_bIsDir;
|
||||
}
|
||||
|
||||
#if SG_HAVE_ICU
|
||||
bool IsDirS(UChar) const {
|
||||
return this->IsDirS((char)0);
|
||||
}
|
||||
#endif
|
||||
|
||||
SG_FileType GetFileTypeS(const char * a_pszPath) const {
|
||||
struct stat sb;
|
||||
if (0 != stat(a_pszPath, &sb)) {
|
||||
return SG_FILETYPE_INVALID;
|
||||
}
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
return SG_FILETYPE_DIR;
|
||||
}
|
||||
if (S_ISREG(sb.st_mode)) {
|
||||
return SG_FILETYPE_FILE;
|
||||
}
|
||||
return SG_FILETYPE_INVALID;
|
||||
}
|
||||
|
||||
#if SG_HAVE_ICU
|
||||
SG_FileType GetFileTypeS(const UChar * a_pszPath) const {
|
||||
char buf[PATH_MAX] = { 0 };
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
u_strToUTF8(buf, sizeof(buf), NULL, a_pszPath, -1, &status);
|
||||
if (U_FAILURE(status)) return SG_FILETYPE_INVALID;
|
||||
return this->GetFileTypeS(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
glob_t m_glob;
|
||||
size_t m_uiCurr;
|
||||
bool m_bIsDir;
|
||||
#if SG_HAVE_ICU
|
||||
mutable UChar m_szBuf[PATH_MAX];
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // DOXYGEN
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MAIN TEMPLATE CLASS
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/*! @brief Implementation of the SimpleGlob class */
|
||||
template<class SOCHAR>
|
||||
class CSimpleGlobTempl : private SimpleGlobBase<SOCHAR>
|
||||
{
|
||||
public:
|
||||
/*! @brief Initialize the class.
|
||||
|
||||
@param a_uiFlags Combination of SG_GLOB flags.
|
||||
@param a_nReservedSlots Number of slots in the argv array that
|
||||
should be reserved. In the returned array these slots
|
||||
argv[0] ... argv[a_nReservedSlots-1] will be left empty for
|
||||
the caller to fill in.
|
||||
*/
|
||||
CSimpleGlobTempl(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0);
|
||||
|
||||
/*! @brief Deallocate all memory buffers. */
|
||||
~CSimpleGlobTempl();
|
||||
|
||||
/*! @brief Initialize (or re-initialize) the class in preparation for
|
||||
adding new filespecs.
|
||||
|
||||
All existing files are cleared. Note that allocated memory is only
|
||||
deallocated at object destruction.
|
||||
|
||||
@param a_uiFlags Combination of SG_GLOB flags.
|
||||
@param a_nReservedSlots Number of slots in the argv array that
|
||||
should be reserved. In the returned array these slots
|
||||
argv[0] ... argv[a_nReservedSlots-1] will be left empty for
|
||||
the caller to fill in.
|
||||
*/
|
||||
int Init(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0);
|
||||
|
||||
/*! @brief Add a new filespec to the glob.
|
||||
|
||||
The filesystem will be immediately scanned for all matching files and
|
||||
directories and they will be added to the glob.
|
||||
|
||||
@param a_pszFileSpec Filespec to add to the glob.
|
||||
|
||||
@return SG_SUCCESS Matching files were added to the glob.
|
||||
@return SG_ERR_NOMATCH Nothing matched the pattern. To ignore this
|
||||
error compare return value to >= SG_SUCCESS.
|
||||
@return SG_ERR_MEMORY Out of memory failure.
|
||||
@return SG_ERR_FAILURE General failure.
|
||||
*/
|
||||
int Add(const SOCHAR *a_pszFileSpec);
|
||||
|
||||
/*! @brief Add an array of filespec to the glob.
|
||||
|
||||
The filesystem will be immediately scanned for all matching files and
|
||||
directories in each filespec and they will be added to the glob.
|
||||
|
||||
@param a_nCount Number of filespec in the array.
|
||||
@param a_rgpszFileSpec Array of filespec to add to the glob.
|
||||
|
||||
@return SG_SUCCESS Matching files were added to the glob.
|
||||
@return SG_ERR_NOMATCH Nothing matched the pattern. To ignore this
|
||||
error compare return value to >= SG_SUCCESS.
|
||||
@return SG_ERR_MEMORY Out of memory failure.
|
||||
@return SG_ERR_FAILURE General failure.
|
||||
*/
|
||||
int Add(int a_nCount, const SOCHAR * const * a_rgpszFileSpec);
|
||||
|
||||
/*! @brief Return the number of files in the argv array.
|
||||
*/
|
||||
inline int FileCount() const { return m_nArgsLen; }
|
||||
|
||||
/*! @brief Return the full argv array. */
|
||||
inline SOCHAR ** Files() {
|
||||
SetArgvArrayType(POINTERS);
|
||||
return m_rgpArgs;
|
||||
}
|
||||
|
||||
/*! @brief Return the a single file. */
|
||||
inline SOCHAR * File(int n) {
|
||||
SG_ASSERT(n >= 0 && n < m_nArgsLen);
|
||||
return Files()[n];
|
||||
}
|
||||
|
||||
private:
|
||||
CSimpleGlobTempl(const CSimpleGlobTempl &); // disabled
|
||||
CSimpleGlobTempl & operator=(const CSimpleGlobTempl &); // disabled
|
||||
|
||||
/*! @brief The argv array has it's members stored as either an offset into
|
||||
the string buffer, or as pointers to their string in the buffer. The
|
||||
offsets are used because if the string buffer is dynamically resized,
|
||||
all pointers into that buffer would become invalid.
|
||||
*/
|
||||
enum ARG_ARRAY_TYPE { OFFSETS, POINTERS };
|
||||
|
||||
/*! @brief Change the type of data stored in the argv array. */
|
||||
void SetArgvArrayType(ARG_ARRAY_TYPE a_nNewType);
|
||||
|
||||
/*! @brief Add a filename to the array if it passes all requirements. */
|
||||
int AppendName(const SOCHAR *a_pszFileName, bool a_bIsDir);
|
||||
|
||||
/*! @brief Grow the argv array to the required size. */
|
||||
bool GrowArgvArray(int a_nNewLen);
|
||||
|
||||
/*! @brief Grow the string buffer to the required size. */
|
||||
bool GrowStringBuffer(size_t a_uiMinSize);
|
||||
|
||||
/*! @brief Compare two (possible NULL) strings */
|
||||
static int fileSortCompare(const void *a1, const void *a2);
|
||||
|
||||
private:
|
||||
unsigned int m_uiFlags;
|
||||
ARG_ARRAY_TYPE m_nArgArrayType; //!< argv is indexes or pointers
|
||||
SOCHAR ** m_rgpArgs; //!< argv
|
||||
int m_nReservedSlots; //!< # client slots in argv array
|
||||
int m_nArgsSize; //!< allocated size of array
|
||||
int m_nArgsLen; //!< used length
|
||||
SOCHAR * m_pBuffer; //!< argv string buffer
|
||||
size_t m_uiBufferSize; //!< allocated size of buffer
|
||||
size_t m_uiBufferLen; //!< used length of buffer
|
||||
SOCHAR m_szPathPrefix[MAX_PATH]; //!< wildcard path prefix
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IMPLEMENTATION
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
template<class SOCHAR>
|
||||
CSimpleGlobTempl<SOCHAR>::CSimpleGlobTempl(
|
||||
unsigned int a_uiFlags,
|
||||
int a_nReservedSlots
|
||||
)
|
||||
{
|
||||
m_rgpArgs = NULL;
|
||||
m_nArgsSize = 0;
|
||||
m_pBuffer = NULL;
|
||||
m_uiBufferSize = 0;
|
||||
|
||||
Init(a_uiFlags, a_nReservedSlots);
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
CSimpleGlobTempl<SOCHAR>::~CSimpleGlobTempl()
|
||||
{
|
||||
if (m_rgpArgs) free(m_rgpArgs);
|
||||
if (m_pBuffer) free(m_pBuffer);
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
int
|
||||
CSimpleGlobTempl<SOCHAR>::Init(
|
||||
unsigned int a_uiFlags,
|
||||
int a_nReservedSlots
|
||||
)
|
||||
{
|
||||
m_nArgArrayType = POINTERS;
|
||||
m_uiFlags = a_uiFlags;
|
||||
m_nArgsLen = a_nReservedSlots;
|
||||
m_nReservedSlots = a_nReservedSlots;
|
||||
m_uiBufferLen = 0;
|
||||
|
||||
if (m_nReservedSlots > 0) {
|
||||
if (!GrowArgvArray(m_nReservedSlots)) {
|
||||
return SG_ERR_MEMORY;
|
||||
}
|
||||
for (int n = 0; n < m_nReservedSlots; ++n) {
|
||||
m_rgpArgs[n] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
int
|
||||
CSimpleGlobTempl<SOCHAR>::Add(
|
||||
const SOCHAR *a_pszFileSpec
|
||||
)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Windows FindFirst/FindNext recognizes forward slash as the same as
|
||||
// backward slash and follows the directories. We need to do the same
|
||||
// when calculating the prefix and when we have no wildcards.
|
||||
SOCHAR szFileSpec[MAX_PATH];
|
||||
SimpleGlobUtil::strcpy_s(szFileSpec, MAX_PATH, a_pszFileSpec);
|
||||
const SOCHAR * pszPath = SimpleGlobUtil::strchr(szFileSpec, '/');
|
||||
while (pszPath) {
|
||||
szFileSpec[pszPath - szFileSpec] = SG_PATH_CHAR;
|
||||
pszPath = SimpleGlobUtil::strchr(pszPath + 1, '/');
|
||||
}
|
||||
a_pszFileSpec = szFileSpec;
|
||||
#endif
|
||||
|
||||
// if this doesn't contain wildcards then we can just add it directly
|
||||
m_szPathPrefix[0] = 0;
|
||||
if (!SimpleGlobUtil::strchr(a_pszFileSpec, '*') &&
|
||||
!SimpleGlobUtil::strchr(a_pszFileSpec, '?'))
|
||||
{
|
||||
SG_FileType nType = this->GetFileTypeS(a_pszFileSpec);
|
||||
if (nType == SG_FILETYPE_INVALID) {
|
||||
if (m_uiFlags & SG_GLOB_NOCHECK) {
|
||||
return AppendName(a_pszFileSpec, false);
|
||||
}
|
||||
return SG_ERR_NOMATCH;
|
||||
}
|
||||
return AppendName(a_pszFileSpec, nType == SG_FILETYPE_DIR);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows doesn't return the directory with the filename, so we need to
|
||||
// extract the path from the search string ourselves and prefix it to the
|
||||
// filename we get back.
|
||||
const SOCHAR * pszFilename =
|
||||
SimpleGlobUtil::strrchr(a_pszFileSpec, SG_PATH_CHAR);
|
||||
if (pszFilename) {
|
||||
SimpleGlobUtil::strcpy_s(m_szPathPrefix, MAX_PATH, a_pszFileSpec);
|
||||
m_szPathPrefix[pszFilename - a_pszFileSpec + 1] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// search for the first match on the file
|
||||
int rc = this->FindFirstFileS(a_pszFileSpec, m_uiFlags);
|
||||
if (rc != SG_SUCCESS) {
|
||||
if (rc == SG_ERR_NOMATCH && (m_uiFlags & SG_GLOB_NOCHECK)) {
|
||||
int ok = AppendName(a_pszFileSpec, false);
|
||||
if (ok != SG_SUCCESS) rc = ok;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// add it and find all subsequent matches
|
||||
int nError, nStartLen = m_nArgsLen;
|
||||
bool bSuccess;
|
||||
do {
|
||||
nError = AppendName(this->GetFileNameS((SOCHAR)0), this->IsDirS((SOCHAR)0));
|
||||
bSuccess = this->FindNextFileS((SOCHAR)0);
|
||||
}
|
||||
while (nError == SG_SUCCESS && bSuccess);
|
||||
SimpleGlobBase<SOCHAR>::FindDone();
|
||||
|
||||
// sort these files if required
|
||||
if (m_nArgsLen > nStartLen && !(m_uiFlags & SG_GLOB_NOSORT)) {
|
||||
if (m_uiFlags & SG_GLOB_FULLSORT) {
|
||||
nStartLen = m_nReservedSlots;
|
||||
}
|
||||
SetArgvArrayType(POINTERS);
|
||||
qsort(
|
||||
m_rgpArgs + nStartLen,
|
||||
m_nArgsLen - nStartLen,
|
||||
sizeof(m_rgpArgs[0]), fileSortCompare);
|
||||
}
|
||||
|
||||
return nError;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
int
|
||||
CSimpleGlobTempl<SOCHAR>::Add(
|
||||
int a_nCount,
|
||||
const SOCHAR * const * a_rgpszFileSpec
|
||||
)
|
||||
{
|
||||
int nResult;
|
||||
for (int n = 0; n < a_nCount; ++n) {
|
||||
nResult = Add(a_rgpszFileSpec[n]);
|
||||
if (nResult != SG_SUCCESS) {
|
||||
return nResult;
|
||||
}
|
||||
}
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
int
|
||||
CSimpleGlobTempl<SOCHAR>::AppendName(
|
||||
const SOCHAR * a_pszFileName,
|
||||
bool a_bIsDir
|
||||
)
|
||||
{
|
||||
// we need the argv array as offsets in case we resize it
|
||||
SetArgvArrayType(OFFSETS);
|
||||
|
||||
// check for special cases which cause us to ignore this entry
|
||||
if ((m_uiFlags & SG_GLOB_ONLYDIR) && !a_bIsDir) {
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
if ((m_uiFlags & SG_GLOB_ONLYFILE) && a_bIsDir) {
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
if ((m_uiFlags & SG_GLOB_NODOT) && a_bIsDir) {
|
||||
if (a_pszFileName[0] == '.') {
|
||||
if (a_pszFileName[1] == '\0') {
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
if (a_pszFileName[1] == '.' && a_pszFileName[2] == '\0') {
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that we have enough room in the argv array
|
||||
if (!GrowArgvArray(m_nArgsLen + 1)) {
|
||||
return SG_ERR_MEMORY;
|
||||
}
|
||||
|
||||
// ensure that we have enough room in the string buffer (+1 for null)
|
||||
size_t uiPrefixLen = SimpleGlobUtil::strlen(m_szPathPrefix);
|
||||
size_t uiLen = uiPrefixLen + SimpleGlobUtil::strlen(a_pszFileName) + 1;
|
||||
if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
|
||||
++uiLen; // need space for the backslash
|
||||
}
|
||||
if (!GrowStringBuffer(m_uiBufferLen + uiLen)) {
|
||||
return SG_ERR_MEMORY;
|
||||
}
|
||||
|
||||
// add this entry. m_uiBufferLen is offset from beginning of buffer.
|
||||
m_rgpArgs[m_nArgsLen++] = (SOCHAR*)m_uiBufferLen;
|
||||
SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen,
|
||||
m_uiBufferSize - m_uiBufferLen, m_szPathPrefix);
|
||||
SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen + uiPrefixLen,
|
||||
m_uiBufferSize - m_uiBufferLen - uiPrefixLen, a_pszFileName);
|
||||
m_uiBufferLen += uiLen;
|
||||
|
||||
// add the directory slash if desired
|
||||
if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
|
||||
const static SOCHAR szDirSlash[] = { SG_PATH_CHAR, 0 };
|
||||
SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen - 2,
|
||||
m_uiBufferSize - (m_uiBufferLen - 2), szDirSlash);
|
||||
}
|
||||
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
void
|
||||
CSimpleGlobTempl<SOCHAR>::SetArgvArrayType(
|
||||
ARG_ARRAY_TYPE a_nNewType
|
||||
)
|
||||
{
|
||||
if (m_nArgArrayType == a_nNewType) return;
|
||||
if (a_nNewType == POINTERS) {
|
||||
SG_ASSERT(m_nArgArrayType == OFFSETS);
|
||||
for (int n = 0; n < m_nArgsLen; ++n) {
|
||||
m_rgpArgs[n] = (m_rgpArgs[n] == (SOCHAR*)-1) ?
|
||||
NULL : m_pBuffer + (size_t) m_rgpArgs[n];
|
||||
}
|
||||
}
|
||||
else {
|
||||
SG_ASSERT(a_nNewType == OFFSETS);
|
||||
SG_ASSERT(m_nArgArrayType == POINTERS);
|
||||
for (int n = 0; n < m_nArgsLen; ++n) {
|
||||
m_rgpArgs[n] = (m_rgpArgs[n] == NULL) ?
|
||||
(SOCHAR*) -1 : (SOCHAR*) (m_rgpArgs[n] - m_pBuffer);
|
||||
}
|
||||
}
|
||||
m_nArgArrayType = a_nNewType;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
bool
|
||||
CSimpleGlobTempl<SOCHAR>::GrowArgvArray(
|
||||
int a_nNewLen
|
||||
)
|
||||
{
|
||||
if (a_nNewLen >= m_nArgsSize) {
|
||||
static const int SG_ARGV_INITIAL_SIZE = 32;
|
||||
int nNewSize = (m_nArgsSize > 0) ?
|
||||
m_nArgsSize * 2 : SG_ARGV_INITIAL_SIZE;
|
||||
while (a_nNewLen >= nNewSize) {
|
||||
nNewSize *= 2;
|
||||
}
|
||||
void * pNewBuffer = realloc(m_rgpArgs, nNewSize * sizeof(SOCHAR*));
|
||||
if (!pNewBuffer) return false;
|
||||
m_nArgsSize = nNewSize;
|
||||
m_rgpArgs = (SOCHAR**) pNewBuffer;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
bool
|
||||
CSimpleGlobTempl<SOCHAR>::GrowStringBuffer(
|
||||
size_t a_uiMinSize
|
||||
)
|
||||
{
|
||||
if (a_uiMinSize >= m_uiBufferSize) {
|
||||
static const int SG_BUFFER_INITIAL_SIZE = 1024;
|
||||
size_t uiNewSize = (m_uiBufferSize > 0) ?
|
||||
m_uiBufferSize * 2 : SG_BUFFER_INITIAL_SIZE;
|
||||
while (a_uiMinSize >= uiNewSize) {
|
||||
uiNewSize *= 2;
|
||||
}
|
||||
void * pNewBuffer = realloc(m_pBuffer, uiNewSize * sizeof(SOCHAR));
|
||||
if (!pNewBuffer) return false;
|
||||
m_uiBufferSize = uiNewSize;
|
||||
m_pBuffer = (SOCHAR*) pNewBuffer;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class SOCHAR>
|
||||
int
|
||||
CSimpleGlobTempl<SOCHAR>::fileSortCompare(
|
||||
const void *a1,
|
||||
const void *a2
|
||||
)
|
||||
{
|
||||
const SOCHAR * s1 = *(const SOCHAR **)a1;
|
||||
const SOCHAR * s2 = *(const SOCHAR **)a2;
|
||||
if (s1 && s2) {
|
||||
return SimpleGlobUtil::strcasecmp(s1, s2);
|
||||
}
|
||||
// NULL sorts first
|
||||
return s1 == s2 ? 0 : (s1 ? 1 : -1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TYPE DEFINITIONS
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/*! @brief ASCII/MBCS version of CSimpleGlob */
|
||||
typedef CSimpleGlobTempl<char> CSimpleGlobA;
|
||||
|
||||
/*! @brief wchar_t version of CSimpleGlob */
|
||||
typedef CSimpleGlobTempl<wchar_t> CSimpleGlobW;
|
||||
|
||||
#if SG_HAVE_ICU
|
||||
/*! @brief UChar version of CSimpleGlob */
|
||||
typedef CSimpleGlobTempl<UChar> CSimpleGlobU;
|
||||
#endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
/*! @brief TCHAR version dependent on if _UNICODE is defined */
|
||||
# if SG_HAVE_ICU
|
||||
# define CSimpleGlob CSimpleGlobU
|
||||
# else
|
||||
# define CSimpleGlob CSimpleGlobW
|
||||
# endif
|
||||
#else
|
||||
/*! @brief TCHAR version dependent on if _UNICODE is defined */
|
||||
# define CSimpleGlob CSimpleGlobA
|
||||
#endif
|
||||
|
||||
#endif // INCLUDED_SimpleGlob
|
1063
Source/EmberCommon/SimpleOpt.h
Normal file
1063
Source/EmberCommon/SimpleOpt.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user