| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- #include "Base.h"
- #include "EncoderArguments.h"
- #include "StringUtil.h"
- #ifdef WIN32
- #define PATH_MAX _MAX_PATH
- #define realpath(A,B) _fullpath(B,A,PATH_MAX)
- #endif
- namespace gameplay
- {
- static EncoderArguments* __instance;
- EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
- _fontSize(0),
- _parseError(false),
- _fontPreview(false),
- _textOutput(false),
- _daeOutput(false)
- {
- __instance = this;
- if (argc > 1)
- {
- // read the options
- std::vector<std::string> arguments;
- for (size_t i = 1; i < argc; ++i)
- {
- arguments.push_back(argv[i]);
- }
- size_t index = 0;
- for (size_t i = 0; i < arguments.size(); ++i)
- {
- if (arguments[i][0] == '-')
- {
- readOption(arguments, &i);
- index = i + 1;
- }
- }
- if (arguments.size() - index == 2)
- {
- setInputfilePath(arguments[index]);
- setOutputfilePath(arguments[index + 1]);
- }
- else if (arguments.size() - index == 1)
- {
- setInputfilePath(arguments[index]);
- }
- }
- else
- {
- _parseError = true;
- }
- }
- EncoderArguments::~EncoderArguments(void)
- {
- }
- EncoderArguments* EncoderArguments::getInstance()
- {
- return __instance;
- }
- const std::string& EncoderArguments::getFilePath() const
- {
- return _filePath;
- }
- const char* EncoderArguments::getFilePathPointer() const
- {
- return _filePath.c_str();
- }
- std::string EncoderArguments::getOutputDirPath() const
- {
- if (_fileOutputPath.size() > 0)
- {
- int pos = _fileOutputPath.find_last_of('/');
- return (pos == -1 ? _fileOutputPath : _fileOutputPath.substr(0, pos));
- }
- else
- {
- int pos = _filePath.find_last_of('/');
- return (pos == -1 ? _filePath : _filePath.substr(0, pos));
- }
- }
- std::string EncoderArguments::getOutputFilePath() const
- {
- if (_fileOutputPath.size() > 0)
- {
- return _fileOutputPath;
- }
- else
- {
- int pos = _filePath.find_last_of('.');
- if (pos > 0)
- {
- std::string outputFilePath(_filePath.substr(0, pos));
- outputFilePath.append(".gpb");
- return outputFilePath;
- }
- else
- {
- std::string outputFilePath(_filePath);
- outputFilePath.append(".gpb");
- return outputFilePath;
- }
- }
- }
- const std::string& EncoderArguments::getDAEOutputPath() const
- {
- return _daeOutputPath;
- }
- const std::vector<std::string>& EncoderArguments::getGroupAnimationNodeId() const
- {
- return _groupAnimationNodeId;
- }
- const std::vector<std::string>& EncoderArguments::getGroupAnimationAnimationId() const
- {
- return _groupAnimationAnimationId;
- }
- bool EncoderArguments::containsGroupNodeId(const std::string& nodeId) const
- {
- return find(_groupAnimationNodeId.begin(), _groupAnimationNodeId.end(), nodeId) != _groupAnimationNodeId.end();
- }
- const std::string EncoderArguments::getAnimationId(const std::string& nodeId) const
- {
- std::vector<std::string>::const_iterator it = find(_groupAnimationNodeId.begin(), _groupAnimationNodeId.end(), nodeId);
- for (size_t i = 0, size = _groupAnimationNodeId.size(); i < size; ++i)
- {
- if (_groupAnimationNodeId[i].compare(nodeId) == 0)
- {
- return _groupAnimationAnimationId[i];
- }
- }
- return "";
- }
- const std::vector<EncoderArguments::HeightmapOption>& EncoderArguments::getHeightmapOptions() const
- {
- return _heightmaps;
- }
- bool EncoderArguments::parseErrorOccured() const
- {
- return _parseError;
- }
- bool EncoderArguments::fileExists() const
- {
- if (_filePath.length() > 0)
- {
- struct stat buf;
- if (stat(_filePath.c_str(), &buf) != -1)
- {
- return true;
- }
- }
- return false;
- }
- void EncoderArguments::printUsage() const
- {
- fprintf(stderr,"Usage: gameplay-encoder [options] <input filepath> <output filepath>\n\n");
- fprintf(stderr,"Supported file extensions:\n");
- fprintf(stderr," .dae\t(COLLADA)\n");
- fprintf(stderr," .fbx\t(FBX)\n");
- fprintf(stderr," .ttf\t(TrueType Font)\n");
- fprintf(stderr,"\n");
- fprintf(stderr,"COLLADA and FBX file options:\n");
- fprintf(stderr," -i <id>\tFilter by node ID.\n");
- fprintf(stderr," -t\t\tWrite text/xml.\n");
- fprintf(stderr," -g <node id> <animation id>\n" \
- "\t\tGroup all animation channels targeting the nodes into a new animation.\n");
- fprintf(stderr," -h \"<node ids>\" <filename>\n" \
- "\t\tGenerates a single heightmap image using meshes from the specified\n" \
- "\t\tnodes. Node id list should be in quotes with a space between each id.\n" \
- "\t\tFilename is the name of the image (PNG) to be saved.\n" \
- "\t\tMultiple -h arguments can be supplied to generate more than one heightmap.\n");
- fprintf(stderr,"\n");
- fprintf(stderr,"TTF file options:\n");
- fprintf(stderr," -s <size>\tSize of the font.\n");
- fprintf(stderr," -p\t\tOutput font preview.\n");
- fprintf(stderr, "\n");
- exit(8);
- }
- bool EncoderArguments::fontPreviewEnabled() const
- {
- return _fontPreview;
- }
- bool EncoderArguments::textOutputEnabled() const
- {
- return _textOutput;
- }
- bool EncoderArguments::DAEOutputEnabled() const
- {
- return _daeOutput;
- }
- const char* EncoderArguments::getNodeId() const
- {
- if (_nodeId.length() == 0)
- {
- return NULL;
- }
- return _nodeId.c_str();
- }
- unsigned int EncoderArguments::getFontSize() const
- {
- return _fontSize;
- }
- EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
- {
- if (_filePath.length() < 5)
- {
- return FILEFORMAT_UNKNOWN;
- }
- // Extract the extension
- std::string ext = "";
- size_t pos = _filePath.find_last_of(".");
- if (pos != std::string::npos)
- {
- ext = _filePath.substr(pos + 1);
- }
-
- // Match every supported extension with its format constant
- if (ext.compare("dae") == 0 || ext.compare("DAE") == 0)
- {
- return FILEFORMAT_DAE;
- }
- if (ext.compare("fbx") == 0 || ext.compare("FBX") == 0)
- {
- return FILEFORMAT_FBX;
- }
- if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
- {
- return FILEFORMAT_TTF;
- }
- if (ext.compare("gpb") == 0 || ext.compare("GPB") == 0)
- {
- return FILEFORMAT_GPB;
- }
- return FILEFORMAT_UNKNOWN;
- }
- void EncoderArguments::readOption(const std::vector<std::string>& options, size_t* index)
- {
- const std::string& str = options[*index];
- if (str.length() == 0 && str[0] != '-')
- {
- return;
- }
- switch (str[1])
- {
- case 'd':
- if (str.compare("-dae") == 0)
- {
- // read one string, make sure not to go out of bounds
- if ((*index + 1) >= options.size())
- {
- fprintf(stderr, "Error: -dae requires 1 argument.\n");
- _parseError = true;
- return;
- }
- (*index)++;
- _daeOutputPath = options[*index];
- _daeOutput = true;
- }
- break;
- case 'g':
- if (str.compare("-groupAnimations") == 0 || str.compare("-g") == 0)
- {
- // read two strings, make sure not to go out of bounds
- if ((*index + 2) >= options.size())
- {
- fprintf(stderr, "Error: -g requires 2 arguments.\n");
- _parseError = true;
- return;
- }
- (*index)++;
- _groupAnimationNodeId.push_back(options[*index]);
- (*index)++;
- _groupAnimationAnimationId.push_back(options[*index]);
- }
- break;
- case 'i':
- case 'o':
- // Node ID
- (*index)++;
- if (*index < options.size())
- {
- _nodeId.assign(options[*index]);
- }
- else
- {
- fprintf(stderr, "Error: missing arguemnt for -%c.\n", str[1]);
- _parseError = true;
- return;
- }
- break;
- case 'h':
- {
- if (str.compare("-heightmap") == 0 || str.compare("-h") == 0)
- {
- (*index)++;
- if (*index < (options.size() + 1))
- {
- _heightmaps.resize(_heightmaps.size() + 1);
- HeightmapOption& heightmap = _heightmaps.back();
- // Split node id list into tokens
- unsigned int length = options[*index].size() + 1;
- char* nodeIds = new char[length];
- strcpy(nodeIds, options[*index].c_str());
- nodeIds[length-1] = 0;
- char* id = strtok(nodeIds, " ");
- while (id)
- {
- heightmap.nodeIds.push_back(id);
- id = strtok(NULL, " ");
- }
- delete[] nodeIds;
- // Store output filename
- (*index)++;
- heightmap.filename = options[*index];
- if (heightmap.filename.empty())
- {
- fprintf(stderr, "Error: missing filename argument for -h|-heightmap.\n");
- _parseError = true;
- return;
- }
-
- // Ensure the output filename has a .png extention
- if (heightmap.filename.length() > 5)
- {
- const char* ext = heightmap.filename.c_str() + (heightmap.filename.length() - 4);
- if (ext[0] != '.' || tolower(ext[1]) != 'p' || tolower(ext[2]) != 'n' || tolower(ext[3]) != 'g')
- heightmap.filename += ".png";
- }
- else
- heightmap.filename += ".png";
- }
- else
- {
- fprintf(stderr, "Error: missing argument for -h|-heightmap.\n");
- _parseError = true;
- return;
- }
- }
- }
- break;
- case 'p':
- _fontPreview = true;
- break;
- case 's':
- // Font Size
- // old format was -s##
- if (str.length() > 2)
- {
- char n = str[2];
- if (n > '0' && n <= '9')
- {
- const char* number = str.c_str() + 2;
- _fontSize = atoi(number);
- break;
- }
- }
- (*index)++;
- if (*index < options.size())
- {
- _fontSize = atoi(options[*index].c_str());
- }
- else
- {
- fprintf(stderr, "Error: missing arguemnt for -%c.\n", str[1]);
- _parseError = true;
- return;
- }
- break;
- case 't':
- _textOutput = true;
- break;
- default:
- break;
- }
- }
- void EncoderArguments::setInputfilePath(const std::string& inputPath)
- {
- _filePath.assign(getRealPath(inputPath));
- }
- void EncoderArguments::setOutputfilePath(const std::string& outputPath)
- {
- if (outputPath.size() > 0 && outputPath[0] != '\0')
- {
- std::string realPath = getRealPath(outputPath);
- if (endsWith(realPath.c_str(), ".gpb"))
- {
- _fileOutputPath.assign(realPath);
- }
- else if (endsWith(outputPath.c_str(), "/"))
- {
- std::string filenameNoExt = getFilenameNoExt(getFilenameFromFilePath(_filePath));
- _fileOutputPath.assign(outputPath);
- _fileOutputPath.append(filenameNoExt);
- _fileOutputPath.append(".gpb");
- }
- else
- {
- std::string filenameNoExt = getFilenameNoExt(getFilenameFromFilePath(realPath));
- int pos = realPath.find_last_of("/");
- if (pos)
- {
- _fileOutputPath = realPath.substr(0, pos);
- _fileOutputPath.append("/");
- _fileOutputPath.append(filenameNoExt);
- _fileOutputPath.append(".gpb");
- }
- }
- }
- }
- std::string EncoderArguments::getRealPath(const std::string& filepath)
- {
- char path[PATH_MAX + 1]; /* not sure about the "+ 1" */
- realpath(filepath.c_str(), path);
- replace_char(path, '\\', '/');
- return std::string(path);
- }
- void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
- {
- for (; *str != '\0'; ++str)
- {
- if (*str == oldChar)
- {
- *str = newChar;
- }
- }
- }
- std::string concat(const std::string& a, const char* b)
- {
- std::string str(a);
- str.append(b);
- return str;
- }
- void unittestsEncoderArguments()
- {
- std::string dir = EncoderArguments::getRealPath(".");
- std::string exePath = EncoderArguments::getRealPath(".");
- exePath.append("/gameplay-encoder.exe");
- const char* exe = exePath.c_str();
- {
- const char* argv[] = {exe, "-g", "root", "movements", "C:\\Git\\gaming\\GamePlay\\gameplay-encoder\\res\\seymour.dae"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getAnimationId("root"), ("movements")));
- assert(equals(args.getGroupAnimationNodeId()[0], ("root")));
- assert(equals(args.getOutputFilePath(), "C:/Git/gaming/GamePlay/gameplay-encoder/res/seymour.gpb"));
- }
- {
- // Test with only input file name (relative)
- const char* argv[] = {exe, "input.dae"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/input.gpb")));
- equals(args.getOutputDirPath(), dir);
- }
- {
- // Test specifying a relative output path
- const char* argv[] = {exe, "input.dae", "output.gpb"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
- }
- {
- // Test specifying a relative output path
- const char* argv[] = {exe, "input.fbx", "output.gpb"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.fbx")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
- }
- {
- // Test specifying a relative output path to a directory
- const char* argv[] = {exe, "input.dae", "stuff/output.gpb"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/stuff/output.gpb")));
- }
- {
- // Test parsing some arguments
- const char* argv[] = {exe, "-dae", "collada.dae", "-t", "input.dae", "output.gpb"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
- assert(args.textOutputEnabled());
- //assert(equals(args.getDAEOutputPath(), concat(dir, "/collada.dae")));
- }
- {
- // Test output file with no file extension
- const char* argv[] = {exe, "input.dae", "output"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
- }
- {
- // Test output file with wrong file extension
- const char* argv[] = {exe, "input.dae", "output.dae"};
- EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
- assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
- assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
- }
- }
- }
|