diff --git a/tools/meta/meta.cpp b/tools/meta/meta.cpp index 7f7c0ac..ea2bce6 100644 --- a/tools/meta/meta.cpp +++ b/tools/meta/meta.cpp @@ -46,6 +46,12 @@ static void version() ); } +static const bx::CommandLineOption s_options[] = +{ + { 'h', "help", 0, NULL, "Display this help and exit." }, + { 'v', "version", 0, NULL, "Output version information and exit." }, +}; + static void help(const char* _error = NULL) { if (NULL != _error) @@ -63,8 +69,12 @@ static void help(const char* _error = NULL) "file without decoding pixel data, similar to the UNIX `file` tool.\n" "\n" "Options:\n" - " -h, --help Display this help and exit.\n" - " -v, --version Output version information and exit.\n" + ); + + bx::Error err; + bx::write(bx::getStdOut(), s_options, BX_COUNTOF(s_options), &err); + + bx::printf( "\n" "For more information, see https://github.com/bkaradzic/bimg\n" ); @@ -162,7 +172,7 @@ static bool processFile(bx::AllocatorI* _allocator, const char* _filePath) int main(int _argc, const char* _argv[]) { - bx::CommandLine cmdLine(_argc, _argv); + bx::CommandLine cmdLine(_argc, _argv, s_options, BX_COUNTOF(s_options) ); if (cmdLine.hasArg('v', "version") ) { @@ -176,23 +186,24 @@ int main(int _argc, const char* _argv[]) return bx::kExitSuccess; } + const char* unknown = cmdLine.findUnknownOption(); + if (NULL != unknown) + { + char error[256]; + bx::snprintf(error, BX_COUNTOF(error), "Unknown option '%s'.", unknown); + help(error); + return bx::kExitFailure; + } + bx::DefaultAllocator allocator; bool any = false; bool ok = true; - for (int32_t ii = 1, num = cmdLine.getNum(); ii < num; ++ii) + for (int32_t ii = 1, num = cmdLine.getNumPositional(); ii < num; ++ii) { - const char* arg = cmdLine.get(ii); - - // Skip options; only positional arguments are treated as files. - if ('-' == arg[0]) - { - continue; - } - any = true; - ok &= processFile(&allocator, arg); + ok &= processFile(&allocator, cmdLine.getPositional(ii) ); } if (!any) diff --git a/tools/texturec/texturec.cpp b/tools/texturec/texturec.cpp index af52430..765d06c 100644 --- a/tools/texturec/texturec.cpp +++ b/tools/texturec/texturec.cpp @@ -897,6 +897,162 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData return output; } +static const char* const s_outputExt[] = +{ + "dds", + "exr", + "hdr", + "ktx", + "ktx2", + "png", + NULL, +}; + +struct FileFormatDesc +{ + const char* ext; + const char* description; +}; + +static const FileFormatDesc s_fileFormatDesc[] = +{ + { "avif", "AV1 Image File Format." }, + { "bmp", "Windows Bitmap." }, + { "dds", "Direct Draw Surface." }, + { "exr", "OpenEXR." }, + { "gif", "Graphics Interchange Format." }, + { "hdr", "Radiance RGBE." }, + { "heic", "High Efficiency Image Coding." }, + { "jpeg", "JPEG Interchange Format." }, + { "jpg", "JPEG Interchange Format." }, + { "ktx", "Khronos Texture." }, + { "ktx2", "Khronos Texture 2." }, + { "pgm", "Portable Gray Map." }, + { "png", "Portable Network Graphics." }, + { "ppm", "Portable Pixel Map." }, + { "psd", "Photoshop Document." }, + { "pvr", "PowerVR." }, + { "tga", "Truevision TGA." }, + { "webp", "WebP." }, +}; + +static bool isInList(const char* const* _list, const bx::StringView& _ext) +{ + for (const char* const* ext = _list; NULL != *ext; ++ext) + { + if (bx::isEqual(_ext, *ext, false) ) + { + return true; + } + } + + return false; +} + +static const char* getFileFormatDesc(const bx::StringView& _ext) +{ + for (uint32_t ii = 0; ii < BX_COUNTOF(s_fileFormatDesc); ++ii) + { + if (bx::isEqual(_ext, s_fileFormatDesc[ii].ext, false) ) + { + return s_fileFormatDesc[ii].description; + } + } + return ""; +} + +static int32_t writeExt(char* _out, int32_t _max, const char* _ext, bool _input, bool _output) +{ + return bx::snprintf(_out, _max, "*.%s (%s%s%s)" + , _ext + , _input ? "input" : "" + , _input && _output ? ", " : "" + , _output ? "output" : "" + ); +} + +static int32_t writeFileFormats(bx::WriterI* _writer, bx::Error* _err) +{ + struct FileFormat + { + const char* ext; + bool input; + bool output; + }; + + FileFormat formats[64]; + int32_t num = 0; + + const char* const* inputExt = bimg::getSupportedExt(); + + for (const char* const* ext = inputExt; NULL != *ext && num < int32_t(BX_COUNTOF(formats) ); ++ext) + { + formats[num++] = { *ext, true, isInList(s_outputExt, *ext) }; + } + + for (const char* const* ext = s_outputExt; NULL != *ext && num < int32_t(BX_COUNTOF(formats) ); ++ext) + { + if (!isInList(inputExt, *ext) ) + { + formats[num++] = { *ext, false, true }; + } + } + + char column[64]; + int32_t width = 0; + + for (int32_t ii = 0; ii < num; ++ii) + { + width = bx::max(width, writeExt(column, sizeof(column), formats[ii].ext, formats[ii].input, formats[ii].output) ); + } + + int32_t total = 0; + + for (int32_t ii = 0; ii < num; ++ii) + { + const FileFormat& format = formats[ii]; + + const int32_t len = writeExt(column, sizeof(column), format.ext, format.input, format.output); + + total += bx::write(_writer, _err, " %s", column); + total += bx::writeRep(_writer, ' ', width - len + 2, _err); + total += bx::write(_writer, _err, "%s\n", getFileFormatDesc(format.ext) ); + } + + return total; +} + +static const bx::CommandLineOption s_options[] = +{ + { 'h', "help", 0, NULL, "Help." }, + { 'v', "version", 0, NULL, "Version information only." }, + { 'f', NULL, 1, "", "Input file path.\n" + "Input and output may also be passed positionally, without\n" + "-f/-o." }, + { 'o', NULL, 1, "", "Output file path." }, + { 't', NULL, 1, "", "Output format type (BC1/2/3/4/5, ETC1, PVR14, etc.)." }, + { 'q', NULL, 1, "", "Encoding quality (default, fastest, highest)." }, + { 'm', "mips", 0, NULL, "Generate mip-maps." }, + { '\0', "mipskip", 1, "", "Skip number of mips." }, + { 'n', "normalmap", 0, NULL, "Input texture is normal map. (Implies --linear)" }, + { '\0', "equirect", 0, NULL, "Input texture is equirectangular projection of cubemap." }, + { '\0', "strip", 0, NULL, "Input texture is horizontal or vertical strip of cubemap." }, + { '\0', "sdf", 0, NULL, "Compute SDF texture." }, + { '\0', "ref", 1, "", "Alpha reference value." }, + { '\0', "iqa", 0, NULL, "Image Quality Assessment" }, + { '\0', "pma", 0, NULL, "Premultiply alpha into RGB channel." }, + { '\0', "linear", 0, NULL, "Input and output texture is linear color space (gamma\n" + "correction won't be applied)." }, + { '\0', "max", 1, "", "Maximum width/height (image will be scaled down and\n" + "aspect ratio will be preserved)" }, + { '\0', "radiance", 1, "", "Radiance cubemap filter. (Lighting model: Phong, PhongBrdf,\n" + "Blinn, BlinnBrdf, GGX)" }, + { '\0', "as", 1, "", "Save as." }, + { '\0', "formats", 0, NULL, "List all supported formats." }, + { '\0', "validate", 0, NULL, "*DEBUG* Validate that output image produced matches after\n" + "loading." }, +}; + void help(const char* _error = NULL, bool _showHelp = true) { if (NULL != _error) @@ -918,49 +1074,25 @@ void help(const char* _error = NULL, bool _showHelp = true) , BIMG_API_VERSION ); + bx::Error err; + bx::printf( "Usage: texturec -f -o [-t ]\n" - + " texturec [-t ]\n" "\n" "Supported file formats:\n" - " *.bmp (input) Windows Bitmap.\n" - " *.dds (input, output) Direct Draw Surface.\n" - " *.exr (input, output) OpenEXR.\n" - " *.gif (input) Graphics Interchange Format.\n" - " *.jpg (input) JPEG Interchange Format.\n" - " *.hdr (input, output) Radiance RGBE.\n" - " *.ktx (input, output) Khronos Texture.\n" - " *.ktx2 (input, output) Khronos Texture 2.\n" - " *.png (input, output) Portable Network Graphics.\n" - " *.psd (input) Photoshop Document.\n" - " *.pvr (input) PowerVR.\n" - " *.tga (input) Truevision TGA.\n" + ); + writeFileFormats(bx::getStdOut(), &err); + + bx::printf( "\n" "Options:\n" - " -h, --help Help.\n" - " -v, --version Version information only.\n" - " -f Input file path.\n" - " -o Output file path.\n" - " -t Output format type (BC1/2/3/4/5, ETC1, PVR14, etc.).\n" - " -q Encoding quality (default, fastest, highest).\n" - " -m, --mips Generate mip-maps.\n" - " --mipskip Skip number of mips.\n" - " -n, --normalmap Input texture is normal map. (Implies --linear)\n" - " --equirect Input texture is equirectangular projection of cubemap.\n" - " --strip Input texture is horizontal or vertical strip of cubemap.\n" - " --sdf Compute SDF texture.\n" - " --ref Alpha reference value.\n" - " --iqa Image Quality Assessment\n" - " --pma Premultiply alpha into RGB channel.\n" - " --linear Input and output texture is linear color space (gamma correction won't be applied).\n" - " --max Maximum width/height (image will be scaled down and\n" - " aspect ratio will be preserved)\n" - " --radiance Radiance cubemap filter. (Lighting model: Phong, PhongBrdf, Blinn, BlinnBrdf, GGX)\n" - " --as Save as.\n" - " --formats List all supported formats.\n" - " --validate *DEBUG* Validate that output image produced matches after loading.\n" + ); + + bx::write(bx::getStdOut(), s_options, BX_COUNTOF(s_options), &err); + bx::printf( "\n" "For additional information, see https://github.com/bkaradzic/bimg\n" ); @@ -1009,7 +1141,7 @@ class AlignedAllocator : public bx::AllocatorI int main(int _argc, const char* _argv[]) { - bx::CommandLine cmdLine(_argc, _argv); + bx::CommandLine cmdLine(_argc, _argv, s_options, BX_COUNTOF(s_options) ); if (cmdLine.hasArg('v', "version") ) { @@ -1052,7 +1184,22 @@ int main(int _argc, const char* _argv[]) return bx::kExitSuccess; } + const char* unknown = cmdLine.findUnknownOption(); + if (NULL != unknown) + { + char error[256]; + bx::snprintf(error, BX_COUNTOF(error), "Unknown option '%s'.", unknown); + help(error); + return bx::kExitFailure; + } + + int32_t positional = 1; + const char* inputFileName = cmdLine.findOption('f'); + inputFileName = NULL != inputFileName + ? inputFileName + : cmdLine.getPositional(positional++) + ; if (NULL == inputFileName) { help("Input file must be specified."); @@ -1060,6 +1207,10 @@ int main(int _argc, const char* _argv[]) } const char* outputFileName = cmdLine.findOption('o'); + outputFileName = NULL != outputFileName + ? outputFileName + : cmdLine.getPositional(positional++) + ; if (NULL == outputFileName) { help("Output file must be specified.");