ImageImporterMain.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Importer/ImageImporter.h>
  6. #include <AnKi/Util/Filesystem.h>
  7. using namespace anki;
  8. namespace {
  9. class Cleanup
  10. {
  11. public:
  12. HeapMemoryPool m_pool = {allocAligned, nullptr};
  13. DynamicArrayRaii<CString> m_inputFilenames = {&m_pool};
  14. StringRaii m_outFilename = {&m_pool};
  15. };
  16. } // namespace
  17. static const char* kUsage = R"(Usage: %s [options] in_files
  18. Options:
  19. -o <filename> : Output filename. If not provided the file will derive it from the input filenames
  20. -t <type> : Image type. One of: 2D, 3D, Cube, 2DArray
  21. -no-alpha : If the image has alpha don't store it. By default it stores it
  22. -store-s3tc <0|1> : Store S3TC images. Default is 1
  23. -store-astc <0|1> : Store ASTC images. Default is 1
  24. -store-raw <0|1> : Store RAW images. Default is 0
  25. -mip-count <number> : Max number of mipmaps. By default store until 4x4
  26. -astc-block-size <XxY> : The size of the ASTC block size. eg 4x4. Default is 8x8
  27. -v : Verbose log
  28. -to-linear : Convert sRGB to linear
  29. -to-srgb : Convert linear to sRGB
  30. -flip-image <0|1> : Flip the image. Default is 1
  31. -hdr-scale <3 floats> : Apply some scale to HDR images. Default is {1 1 1}
  32. -hdr-bias <3 floats> : Apply some bias to HDR images. Default is {0 0 0}
  33. )";
  34. static Error parseCommandLineArgs(int argc, char** argv, ImageImporterConfig& config, Cleanup& cleanup)
  35. {
  36. config.m_compressions = ImageBinaryDataCompression::kS3tc | ImageBinaryDataCompression::kAstc;
  37. config.m_noAlpha = false;
  38. config.m_astcBlockSize = UVec2(8u);
  39. // Parse config
  40. if(argc < 2)
  41. {
  42. // Need at least 1 input
  43. return Error::kUserData;
  44. }
  45. I i;
  46. for(i = 1; i < argc; i++)
  47. {
  48. CString arg = argv[i];
  49. if(arg == "-o")
  50. {
  51. ++i;
  52. if(i >= argc)
  53. {
  54. return Error::kUserData;
  55. }
  56. cleanup.m_outFilename = argv[i];
  57. }
  58. else if(arg == "-t")
  59. {
  60. ++i;
  61. if(i >= argc)
  62. {
  63. return Error::kUserData;
  64. }
  65. if(CString(argv[i]) == "2D")
  66. {
  67. config.m_type = ImageBinaryType::k2D;
  68. }
  69. else if(CString(argv[i]) == "3D")
  70. {
  71. config.m_type = ImageBinaryType::k3D;
  72. }
  73. else if(CString(argv[i]) == "Cube")
  74. {
  75. config.m_type = ImageBinaryType::kCube;
  76. }
  77. else if(CString(argv[i]) == "2DArray")
  78. {
  79. config.m_type = ImageBinaryType::k2DArray;
  80. }
  81. else
  82. {
  83. return Error::kUserData;
  84. }
  85. }
  86. else if(CString(argv[i]) == "-no-alpha")
  87. {
  88. config.m_noAlpha = true;
  89. }
  90. else if(CString(argv[i]) == "-store-s3tc")
  91. {
  92. ++i;
  93. if(i >= argc)
  94. {
  95. return Error::kUserData;
  96. }
  97. if(CString(argv[i]) == "1")
  98. {
  99. config.m_compressions |= ImageBinaryDataCompression::kS3tc;
  100. }
  101. else if(CString(argv[i]) == "0")
  102. {
  103. config.m_compressions = config.m_compressions & ~ImageBinaryDataCompression::kS3tc;
  104. }
  105. else
  106. {
  107. return Error::kUserData;
  108. }
  109. }
  110. else if(CString(argv[i]) == "-store-astc")
  111. {
  112. ++i;
  113. if(i >= argc)
  114. {
  115. return Error::kUserData;
  116. }
  117. if(CString(argv[i]) == "1")
  118. {
  119. config.m_compressions |= ImageBinaryDataCompression::kAstc;
  120. }
  121. else if(CString(argv[i]) == "0")
  122. {
  123. config.m_compressions = config.m_compressions & ~ImageBinaryDataCompression::kAstc;
  124. }
  125. else
  126. {
  127. return Error::kUserData;
  128. }
  129. }
  130. else if(CString(argv[i]) == "-store-raw")
  131. {
  132. ++i;
  133. if(i >= argc)
  134. {
  135. return Error::kUserData;
  136. }
  137. if(CString(argv[i]) == "1")
  138. {
  139. config.m_compressions |= ImageBinaryDataCompression::kRaw;
  140. }
  141. else if(CString(argv[i]) == "0")
  142. {
  143. config.m_compressions = config.m_compressions & ~ImageBinaryDataCompression::kRaw;
  144. }
  145. else
  146. {
  147. return Error::kUserData;
  148. }
  149. }
  150. else if(CString(argv[i]) == "-astc-block-size")
  151. {
  152. ++i;
  153. if(i >= argc)
  154. {
  155. return Error::kUserData;
  156. }
  157. if(CString(argv[i]) == "4x4")
  158. {
  159. config.m_astcBlockSize = UVec2(4u);
  160. }
  161. else if(CString(argv[i]) == "8x8")
  162. {
  163. config.m_astcBlockSize = UVec2(8u);
  164. }
  165. else
  166. {
  167. return Error::kUserData;
  168. }
  169. }
  170. else if(CString(argv[i]) == "-mip-count")
  171. {
  172. ++i;
  173. if(i >= argc)
  174. {
  175. return Error::kUserData;
  176. }
  177. ANKI_CHECK(CString(argv[i]).toNumber(config.m_mipmapCount));
  178. }
  179. else if(CString(argv[i]) == "-v")
  180. {
  181. Logger::getSingleton().enableVerbosity(true);
  182. }
  183. else if(CString(argv[i]) == "-to-linear")
  184. {
  185. config.m_sRgbToLinear = true;
  186. }
  187. else if(CString(argv[i]) == "-to-srgb")
  188. {
  189. config.m_linearToSRgb = true;
  190. }
  191. else if(CString(argv[i]) == "-flip-image")
  192. {
  193. ++i;
  194. if(i >= argc)
  195. {
  196. return Error::kUserData;
  197. }
  198. if(CString(argv[i]) == "1")
  199. {
  200. config.m_flipImage = true;
  201. }
  202. else if(CString(argv[i]) == "0")
  203. {
  204. config.m_flipImage = false;
  205. }
  206. else
  207. {
  208. return Error::kUserData;
  209. }
  210. }
  211. else if(CString(argv[i]) == "-hdr-scale")
  212. {
  213. ++i;
  214. if(i + 2 >= argc)
  215. {
  216. return Error::kUserData;
  217. }
  218. F32 x, y, z;
  219. ANKI_CHECK(CString(argv[i++]).toNumber(x));
  220. ANKI_CHECK(CString(argv[i++]).toNumber(y));
  221. ANKI_CHECK(CString(argv[i]).toNumber(z));
  222. config.m_hdrScale = Vec3(x, y, z);
  223. }
  224. else if(CString(argv[i]) == "-hdr-bias")
  225. {
  226. ++i;
  227. if(i + 2 >= argc)
  228. {
  229. return Error::kUserData;
  230. }
  231. F32 x, y, z;
  232. ANKI_CHECK(CString(argv[i++]).toNumber(x));
  233. ANKI_CHECK(CString(argv[i++]).toNumber(y));
  234. ANKI_CHECK(CString(argv[i]).toNumber(z));
  235. config.m_hdrBias = Vec3(x, y, z);
  236. }
  237. else
  238. {
  239. // Probably input, break
  240. break;
  241. }
  242. }
  243. // Inputs
  244. for(; i < argc; ++i)
  245. {
  246. cleanup.m_inputFilenames.emplaceBack(argv[i]);
  247. }
  248. if(cleanup.m_inputFilenames.getSize() == 0)
  249. {
  250. return Error::kUserData;
  251. }
  252. if(cleanup.m_outFilename.isEmpty())
  253. {
  254. CString infname = cleanup.m_inputFilenames[0];
  255. StringRaii ext(&cleanup.m_pool);
  256. getFilepathExtension(infname, ext);
  257. getFilepathFilename(infname, cleanup.m_outFilename);
  258. if(ext.getLength() > 0)
  259. {
  260. cleanup.m_outFilename.replaceAll(ext, "ankitex");
  261. }
  262. else
  263. {
  264. cleanup.m_outFilename.append(".ankitex");
  265. }
  266. }
  267. config.m_inputFilenames = ConstWeakArray<CString>(cleanup.m_inputFilenames);
  268. config.m_outFilename = cleanup.m_outFilename;
  269. return Error::kNone;
  270. }
  271. int main(int argc, char** argv)
  272. {
  273. HeapMemoryPool pool(allocAligned, nullptr);
  274. ImageImporterConfig config;
  275. config.m_pool = &pool;
  276. Cleanup cleanup;
  277. if(parseCommandLineArgs(argc, argv, config, cleanup))
  278. {
  279. ANKI_IMPORTER_LOGE(kUsage, argv[0]);
  280. return 1;
  281. }
  282. StringRaii tmp(&pool);
  283. if(getTempDirectory(tmp))
  284. {
  285. ANKI_IMPORTER_LOGE("getTempDirectory() failed");
  286. return 1;
  287. }
  288. config.m_tempDirectory = tmp;
  289. #if ANKI_OS_WINDOWS
  290. config.m_compressonatorFilename =
  291. ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Windows64/Compressonator/compressonatorcli.exe";
  292. config.m_astcencFilename = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Windows64/astcenc-avx2.exe";
  293. #elif ANKI_OS_LINUX
  294. config.m_compressonatorFilename = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Linux64/Compressonator/compressonatorcli";
  295. config.m_astcencFilename = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Linux64/astcenc-avx2";
  296. #else
  297. # error "Unupported"
  298. #endif
  299. ANKI_IMPORTER_LOGI("Image importing started: %s", config.m_outFilename.cstr());
  300. if(importImage(config))
  301. {
  302. ANKI_IMPORTER_LOGE("Importing failed");
  303. return 1;
  304. }
  305. ANKI_IMPORTER_LOGI("Image importing completed: %s", config.m_outFilename.cstr());
  306. return 0;
  307. }