forked from KhronosGroup/KTX-Software
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommand_create.cpp
More file actions
2713 lines (2417 loc) · 133 KB
/
command_create.cpp
File metadata and controls
2713 lines (2417 loc) · 133 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright 2022-2023 The Khronos Group Inc.
// Copyright 2022-2023 RasterGrid Kft.
// SPDX-License-Identifier: Apache-2.0
#include "command.h"
#include "encode_utils_common.h"
#include "platform_utils.h"
#include "metrics_utils.h"
#include "deflate_utils.h"
#include "encode_utils_basis.h"
#include "encode_utils_astc.h"
#include "format_descriptor.h"
#include "formats.h"
#include "utility.h"
#include <filesystem>
#include <iostream>
#include <regex>
#include <sstream>
#include <cxxopts.hpp>
#include <fmt/ostream.h>
#include <fmt/printf.h>
#include "ktx.h"
#include "image.hpp"
#include "imageio.h"
/** @file
* @~English
* @brief @b create command implementation.
*/
// -------------------------------------------------------------------------------------------------
namespace ktx {
struct ColorSpaceInfo {
khr_df_transfer_e usedInputTransferFunction;
khr_df_primaries_e usedInputPrimaries;
std::unique_ptr<const TransferFunction> srcTransferFunction{};
std::unique_ptr<const TransferFunction> dstTransferFunction{};
std::unique_ptr<const ColorPrimaries> srcColorPrimaries{};
std::unique_ptr<const ColorPrimaries> dstColorPrimaries{};
};
// -------------------------------------------------------------------------------------------------
struct OptionsCreate {
inline static const char* kFormat = "format";
inline static const char* k1D = "1d";
inline static const char* kCubemap = "cubemap";
inline static const char* kRaw = "raw";
inline static const char* kWidth = "width";
inline static const char* kHeight = "height";
inline static const char* kDepth = "depth";
inline static const char* kLayers = "layers";
inline static const char* kLevels = "levels";
inline static const char* kRuntimeMipmap = "runtime-mipmap";
inline static const char* kGenerateMipmap = "generate-mipmap";
inline static const char* kEncode = "encode";
inline static const char* kNormalize = "normalize";
inline static const char* kSwizzle = "swizzle";
inline static const char* kInputSwizzle = "input-swizzle";
inline static const char* kAssignOetf = "assign-oetf";
inline static const char* kAssignTf = "assign-tf";
inline static const char* kAssignPrimaries = "assign-primaries";
inline static const char* kAssignTexcoordOrigin = "assign-texcoord-origin";
inline static const char* kConvertOetf = "convert-oetf";
inline static const char* kConvertTf = "convert-tf";
inline static const char* kConvertPrimaries = "convert-primaries";
inline static const char* kConvertTexcoordOrigin = "convert-texcoord-origin";
inline static const char* kFailOnColorConversions = "fail-on-color-conversions";
inline static const char* kWarnOnColorConversions = "warn-on-color-conversions";
inline static const char* kNoWarnOnColorConversions = "no-warn-on-color-conversions";
inline static const char* kFailOnOriginChanges = "fail-on-origin-changes";
inline static const char* kWarnOnOriginChanges = "warn-on-origin-changes";
inline static const char* kMipmapFilter = "mipmap-filter";
inline static const char* kMipmapFilterScale = "mipmap-filter-scale";
inline static const char* kMipmapWrap = "mipmap-wrap";
bool _1d = false;
bool cubemap = false;
VkFormat vkFormat = VK_FORMAT_UNDEFINED;
FormatDescriptor formatDesc;
bool raw = false;
std::optional<uint32_t> width;
std::optional<uint32_t> height;
std::optional<uint32_t> depth;
std::optional<uint32_t> layers;
std::optional<uint32_t> levels;
bool mipmapRuntime = false;
bool mipmapGenerate = false;
std::optional<std::string> mipmapFilter;
std::string defaultMipmapFilter = "lanczos4";
std::optional<float> mipmapFilterScale;
float defaultMipmapFilterScale = 1.0f;
std::optional<basisu::Resampler::Boundary_Op> mipmapWrap;
basisu::Resampler::Boundary_Op defaultMipmapWrap = basisu::Resampler::Boundary_Op::BOUNDARY_WRAP;
std::optional<std::string> swizzle; /// Sets KTXswizzle
std::optional<std::string> swizzleInput; /// Used to swizzle the input image data
std::optional<khr_df_transfer_e> convertTF = {};
std::optional<khr_df_transfer_e> assignTF = {};
std::optional<khr_df_primaries_e> assignPrimaries = {};
std::optional<khr_df_primaries_e> convertPrimaries = {};
std::optional<ImageSpec::Origin> assignTexcoordOrigin;
std::optional<ImageSpec::Origin> convertTexcoordOrigin;
bool failOnColorConversions = false;
bool warnOnColorConversions = false;
bool noWarnOnColorConversions = false;
bool failOnOriginChanges = false;
bool warnOnOriginChanges = false;
bool normalize = false;
void init(cxxopts::Options& opts) {
opts.add_options()
(kFormat, "KTX format enum that specifies the image data format."
" The enum names are matching the VkFormats without the VK_FORMAT_ prefix."
" The VK_FORMAT_ prefix is ignored if present."
"\nWhen used with --encode it specifies the target format before the encoding step."
" In this case it must be one of:"
"\n R8_UNORM"
"\n R8_SRGB"
"\n R8G8_UNORM"
"\n R8G8_SRGB"
"\n R8G8B8_UNORM"
"\n R8G8B8_SRGB"
"\n R8G8B8A8_UNORM"
"\n R8G8B8A8_SRGB"
"\nIf the format is an ASTC format the ASTC encoder specific options become valid,"
" otherwise they are ignored."
"\nThe format will be used to verify and load all input files into a texture before encoding."
" Case insensitive. Required.", cxxopts::value<std::string>(), "<enum>")
(k1D, "Create a 1D texture. If not set the texture will be a 2D or 3D texture.")
(kCubemap, "Create a cubemap texture. If not set the texture will be a 2D or 3D texture.")
(kRaw, "Create from raw image data.")
(kWidth, "Base level width in pixels.", cxxopts::value<uint32_t>(), "[0-9]+")
(kHeight, "Base level height in pixels.", cxxopts::value<uint32_t>(), "[0-9]+")
(kDepth, "Base level depth in pixels. If set the texture will be a 3D texture.", cxxopts::value<uint32_t>(), "[0-9]+")
(kLayers, "Number of layers. If set the texture will be an array texture.", cxxopts::value<uint32_t>(), "[0-9]+")
(kLevels, "Number of mip levels.", cxxopts::value<uint32_t>(), "[0-9]+")
(kRuntimeMipmap, "Runtime mipmap generation mode.")
(kGenerateMipmap, "Causes mipmaps to be generated during texture creation."
" It enables the use of \'Generate Mipmap\' options."
" If the --levels is not specified the maximum possible mip level will be generated."
" This option is mutually exclusive with --runtime-mipmap and cannot be used with UINT or 3D textures.")
(kEncode, "Encode the created KTX file. Case insensitive."
"\nPossible options are: basis-lz | uastc", cxxopts::value<std::string>(), "<codec>")
(kNormalize, "Normalize input normals to have a unit length. Only valid for\n"
"linear normal textures with 2 or more components. For 2-component\n"
"inputs 2D unit normals are calculated. Do not use these 2D unit\n"
"normals to generate X+Y normals with --normal-mode. For 4-component\n"
"inputs a 3D unit normal is calculated. 1.0 is used for the value of\n"
"the 4th component. Cannot be used with --raw.")
(kSwizzle, "KTX swizzle metadata.", cxxopts::value<std::string>(), "[rgba01]{4}")
(kInputSwizzle, "Pre-swizzle input channels.", cxxopts::value<std::string>(), "[rgba01]{4}")
(kAssignTf, "Force the created texture to have the specified transfer function, ignoring"
" the transfer function of the input file(s). Possible options match the khr_df_transfer_e"
" enumerators without the KHR_DF_TRANSFER_ prefix. The KHR_DF_TRANSFER_ prefix is ignored"
" if present. Case insensitive."
"\nThe options are:"
" linear | srgb | srgb_eotf | scrgb | scrgb_eotf | itu | itu_oetf | bt601 | bt601_oetf | bt709 | bt709_oetf |"
" bt2020 | bt2020_oetf | smpte170m | smpte170m_oetf | smpte170m_eotf | ntsc | ntsc_eotf | slog | slog_oetf |"
" slog2 | slog2_oetf | bt1886 | bt1886_eotf | hlg_oetf | hlg_eotf | pq_oetf | pg_eotf | dcip3 | dcip3_eotf |"
" pal_oetf | pal625_eotf | st240 | st240_oetf | st240_eotf | acescc | acescc_oetf | acescct | acescct_oetf |"
" abobergb | adobergb_eotf",
cxxopts::value<std::string>(), "<tf>")
(kAssignOetf, "Same as --assign-tf. Deprecated.", cxxopts::value<std::string>(), "<tf>")
(kAssignPrimaries, "Force the created texture to have the specified color primaries, ignoring"
" the color primaries of the input file(s). Possible options match the khr_df_primaries_e"
" enumerators without the KHR_DF_PRIMARIES_ prefix. The KHR_DF_PRIMARIES_ prefix is ignored"
" if present. Case insensitive."
"\nThe options are:"
" none | bt709 | srgb | bt601_ebu | bt601_smpte | bt2020 | ciexyz | aces | acescc | ntsc1953 | pal525 | displayp3 | adobergb.",
cxxopts::value<std::string>(), "<primaries>")
(kAssignTexcoordOrigin, "Force the created texture to indicate that the texture coordinate"
" origin s=0, t=0 is at the specified corner of the image. Case insensitive."
"\nPossible options are top-left | bottom-left. -front | -back can be appended and"
" one of these is required when --depth is specified. Must be top-left if --cubemap"
" is specified."
"\nAbsent --convert-texcoord-origin, the effect of this option is to cause KTXorientation"
" metadata indicating the specified origin to be written to the output file.",
cxxopts::value<std::string>(), "<origin>")
(kConvertTf, "Convert the input image(s) to the specified transfer function, if different"
" from the transfer function of the input file(s). If both this and --assign-tf are specified,"
" conversion will be performed from the assigned transfer function to the transfer function"
" specified by this option, if different. Case insensitive."
"\nPossible options are: linear | srgb. The following srgb aliases are also supported:"
" srgb_eotf | scrgb | scrgb_eotf",
cxxopts::value<std::string>(), "<tf>")
(kConvertOetf, "Same as --convert-tf. Deprecated.", cxxopts::value<std::string>(), "<tf>")
(kConvertPrimaries, "Convert the image image(s) to the specified color primaries, if different"
" from the color primaries of the input file(s) or the one specified by --assign-primaries."
" If both this and --assign-primaries are specified, conversion will be performed from "
" the assigned primaries to the primaries specified by this option, if different."
" This option is not allowed to be specified when --assign-primaries is set to 'none'."
" Possible options match the khr_df_transfer_e enumerators without the KHR_DF_TRANSFER_ prefix."
" The KHR_DF_PRIMARIES_ prefix is ignored if present. Case insensitive."
"\nThe options are:"
" bt709 | srgb | bt601_ebu | bt601_smpte | bt2020 | ciexyz | aces | acescc | ntsc1953 | pal525 | displayp3 | adobergb.",
cxxopts::value<std::string>(), "<primaries>")
(kConvertTexcoordOrigin, "Convert the input image(s) so the texture coordinate origin s=0,"
" t=0, is at the specified corner of the image. If both this and --assign-texcoord-origin"
" are specified, conversion will be performed from the assigned origin to the origin"
" specified by this option, if different. Case insensitive."
"\nPossible options are top-left | bottom-left. -front | -back can be appended and"
" one of these is required when --depth is specified. Must be top-left if --cubemap"
" is specified."
"\nInput images whose origin does not match corner will be flipped vertically."
" KTXorientation metadata indicating the specified origin is written to the output file.",
cxxopts::value<std::string>(), "<origin>")
(kFailOnColorConversions, "Generates an error if any of the input images would need to be color converted.")
(kWarnOnColorConversions, "Generates a warning if any of the input images are color converted.")
(kNoWarnOnColorConversions, "Disable all warnings about color conversions including that for"
" visually lossy conversions. Overrides --warn-on-color-conversions should both be specified.")
(kFailOnOriginChanges, "Generates an error if any of the input images would need to have their origin changed.")
(kWarnOnOriginChanges, "Generates a warning if any of the input images have their origin changed.");
opts.add_options("Generate Mipmap")
(kMipmapFilter, "Specifies the filter to use when generating the mipmaps. Case insensitive."
"\nPossible options are:"
" box | tent | bell | b-spline | mitchell | blackman | lanczos3 | lanczos4 | lanczos6 |"
" lanczos12 | kaiser | gaussian | catmullrom | quadratic_interp | quadratic_approx | "
" quadratic_mix."
" Defaults to lanczos4.",
cxxopts::value<std::string>(), "<filter>")
(kMipmapFilterScale, "The filter scale to use. Defaults to 1.0.", cxxopts::value<float>(), "<float>")
(kMipmapWrap, "Specify how to sample pixels near the image boundaries. Case insensitive."
"\nPossible options are:"
" wrap | reflect | clamp."
" Defaults to clamp.", cxxopts::value<std::string>(), "<mode>");
}
std::optional<khr_df_transfer_e> parseTransferFunction(cxxopts::ParseResult& args,
const char* argName,
const char* deprArgName,
Reporter& report) const {
// Many of these are aliases of others. To prevent breakage, in the
// unlikely event one is changed to not be an alias, the aliased
// enumerator names are used.
static const std::unordered_map<std::string, khr_df_transfer_e> values{
{ "NONE", KHR_DF_TRANSFER_UNSPECIFIED },
{ "LINEAR", KHR_DF_TRANSFER_LINEAR },
{ "SRGB", KHR_DF_TRANSFER_SRGB },
{ "SRGB_EOTF", KHR_DF_TRANSFER_SRGB_EOTF }, // SRGB
{ "SCRGB", KHR_DF_TRANSFER_SCRGB }, // SRGB
{ "SCRGB_EOTF", KHR_DF_TRANSFER_SRGB_EOTF }, // SRGB
{ "ITU", KHR_DF_TRANSFER_ITU },
{ "ITU_OETF", KHR_DF_TRANSFER_ITU_OETF }, // ITU
{ "BT601", KHR_DF_TRANSFER_BT601_OETF }, // ITU
{ "BT601_OETF", KHR_DF_TRANSFER_BT601_OETF }, // ITU
{ "BT709", KHR_DF_TRANSFER_BT709_OETF }, // ITU
{ "BT709_OETF", KHR_DF_TRANSFER_BT709_OETF }, // ITU
{ "BT2020", KHR_DF_TRANSFER_BT2020_OETF }, // ITU
{ "BT2020_OETF", KHR_DF_TRANSFER_BT2020_OETF }, // ITU
{ "SMPTE170M", KHR_DF_TRANSFER_SMTPE170M }, // ITU
{ "SMPTE170M_EOTF", KHR_DF_TRANSFER_SMTPE170M_EOTF }, // ITU
{ "SMPTE170M_OETF", KHR_DF_TRANSFER_SMTPE170M_OETF }, // ITU
{ "NTSC", KHR_DF_TRANSFER_NTSC },
{ "NTSC_EOTF", KHR_DF_TRANSFER_NTSC_EOTF }, // NTSC
{ "SLOG", KHR_DF_TRANSFER_SLOG },
{ "SLOG_OETF", KHR_DF_TRANSFER_SLOG_OETF }, // SLOG
{ "SLOG2", KHR_DF_TRANSFER_SLOG2 },
{ "SLOG2_OETF", KHR_DF_TRANSFER_SLOG2_OETF }, // SLOG2
{ "BT1886", KHR_DF_TRANSFER_BT1886 },
{ "BT1886_EOTF", KHR_DF_TRANSFER_BT1886_EOTF }, // BT1886
{ "HLG_OETF", KHR_DF_TRANSFER_HLG_OETF },
{ "HLG_EOTF", KHR_DF_TRANSFER_HLG_EOTF },
{ "PQ_OETF", KHR_DF_TRANSFER_PQ_OETF },
{ "PQ_EOTF", KHR_DF_TRANSFER_PQ_EOTF },
{ "DCIP3", KHR_DF_TRANSFER_DCIP3 },
{ "DCIP3_EOTF", KHR_DF_TRANSFER_DCIP3_EOTF }, // DCIP3
{ "PAL_OETF", KHR_DF_TRANSFER_PAL_OETF },
{ "PAL625_EOTF", KHR_DF_TRANSFER_PAL625_EOTF },
{ "ST240", KHR_DF_TRANSFER_ST240 },
{ "ST240_EOTF", KHR_DF_TRANSFER_ST240_EOTF }, // ST240
{ "ST240_OETF", KHR_DF_TRANSFER_ST240_OETF }, // ST240
{ "ACESCC", KHR_DF_TRANSFER_ACESCC },
{ "ACESCC_OETF", KHR_DF_TRANSFER_ACESCC_OETF }, // ACESCC
{ "ACESCCT", KHR_DF_TRANSFER_ACESCCT },
{ "ACESCCT_OETF", KHR_DF_TRANSFER_ACESCCT_OETF }, // ACESCCT
{ "ADOBERGB", KHR_DF_TRANSFER_ADOBERGB },
{ "ADOBERGB_EOTF", KHR_DF_TRANSFER_ADOBERGB_EOTF }, // ADOBERGB
{ "HLG_UNNORMALIZED_OETF", KHR_DF_TRANSFER_HLG_UNNORMALIZED_OETF },
};
std::optional<khr_df_transfer_e> result = {};
const char* argNameToUse = nullptr;
if (args[argName].count()) {
argNameToUse = argName;
} else if (args[deprArgName].count()) { // Prefer non-depcrecated name.
report.warning("Option --{} is deprecated and will be removed in the next release. Use --{} instead.",
deprArgName, argName);
argNameToUse = deprArgName;
}
if (argNameToUse) {
auto transferStr = to_upper_copy(args[argNameToUse].as<std::string>());
const std::string prefixStr = "KHR_DF_TRANSFER_";
if (transferStr.find(prefixStr) == 0) {
transferStr.erase(transferStr.begin(),
transferStr.begin() + prefixStr.size());
}
const auto it = values.find(transferStr);
if (it != values.end()) {
result = it->second;
} else {
report.fatal_usage("Invalid or unsupported transfer specified as --{} argument: \"{}\".",
argNameToUse, args[argNameToUse].as<std::string>());
}
}
return result;
}
std::optional<khr_df_primaries_e> parseColorPrimaries(cxxopts::ParseResult& args, const char* argName, Reporter& report) const {
static const std::unordered_map<std::string, khr_df_primaries_e> values{
{ "NONE", KHR_DF_PRIMARIES_UNSPECIFIED },
{ "BT709", KHR_DF_PRIMARIES_BT709 },
{ "SRGB", KHR_DF_PRIMARIES_SRGB },
{ "BT601_EBU", KHR_DF_PRIMARIES_BT601_EBU },
{ "BT601_SMPTE", KHR_DF_PRIMARIES_BT601_SMPTE },
{ "BT2020", KHR_DF_PRIMARIES_BT2020 },
{ "CIEXYZ", KHR_DF_PRIMARIES_CIEXYZ },
{ "ACES", KHR_DF_PRIMARIES_ACES },
{ "ACESCC", KHR_DF_PRIMARIES_ACESCC },
{ "NTSC1953", KHR_DF_PRIMARIES_NTSC1953 },
{ "PAL525", KHR_DF_PRIMARIES_PAL525 },
{ "DISPLAYP3", KHR_DF_PRIMARIES_DISPLAYP3 },
{ "ADOBERGB", KHR_DF_PRIMARIES_ADOBERGB },
};
std::optional<khr_df_primaries_e> result = {};
if (args[argName].count()) {
auto primariesStr = to_upper_copy(args[argName].as<std::string>());
const std::string prefixStr = "KHR_DF_PRIMARIES_";
if (primariesStr.find(prefixStr) == 0) {
primariesStr.erase(primariesStr.begin(),
primariesStr.begin() + prefixStr.size());
}
const auto it = values.find(primariesStr);
if (it != values.end()) {
result = it->second;
} else {
report.fatal_usage("Invalid or unsupported primaries specified as --{} argument: \"{}\".", argName,
args[argName].as<std::string>());
}
}
return result;
}
std::optional<ImageSpec::Origin> parseTexcoordOrigin(cxxopts::ParseResult& args, uint32_t numDimensions, const char* argName, Reporter& report) const {
std::optional<ImageSpec::Origin> result;
if (args[argName].count()) {
// RE to extract origin for each dimension.
// - Match 0 is whole matching string.
// - Match 1 is the y origin.
// - Match 2 is the x origin.
// - Match 3 is the z origin. Empty string, if not specified.
// Use raw literal to avoid excess blackslashes
std::regex re(R"--((?:\b(top|bottom)\b-)(?:\b(left)\b)(?:-\b(front|back)\b)?)--");
// For when support for right origin and 1d textures is added.
// y dimension made optional ꜜ right added ꜜ
//std::regex re(R"--((?:\b(top|bottom)\b-)?(?:\b(left|right)\b)(?:-\b(front|back)\b)?)--");
// "auto" here leads to no matching function call for regex_match.
const std::string& originStr = to_lower_copy(args[argName].as<std::string>());
std::smatch sm;
std::regex_match(originStr.begin(), originStr.end(), sm, re);
#if DEBUG_REGEX
std::cout << "match size: " << sm.size() << '\n';
for(uint32_t i = 0; i < sm.size(); i++) {
std::cout << "match " << i << ": " << "\"" << sm.str(i) << "\"" << '\n';
}
#endif
if (sm.empty()) {
report.fatal_usage("Invalid or unsupported origin specified as --{} argument: \"{}\".", argName, originStr);
}
if (numDimensions == 3 && sm.str(3).empty()) {
report.fatal_usage("Z origin must be specified in --{} argument for a 3D texture.", argName);
}
ImageSpec::Origin orig;
// Remember, compare returns 0 for a match.
orig.x = sm.str(2).compare("left") ? ImageSpec::Origin::eRight
: ImageSpec::Origin::eLeft;
orig.y = sm.str(1).compare("bottom") ? ImageSpec::Origin::eTop
: ImageSpec::Origin::eBottom;
if (args[kCubemap].count()) {
if (orig.x != ImageSpec::Origin::eLeft || orig.y != ImageSpec::Origin::eTop) {
report.fatal_usage("--{} argument must be top-left for a cubemap.", argName);
}
}
if (numDimensions == 3)
orig.z = sm.str(3).compare("front") ? ImageSpec::Origin::eFront
: ImageSpec::Origin::eBack;
result = std::move(orig);
}
return result;
}
void process(cxxopts::Options&, cxxopts::ParseResult& args, Reporter& report) {
_1d = args[k1D].as<bool>();
cubemap = args[kCubemap].as<bool>();
raw = args[kRaw].as<bool>();
if (args[kWidth].count())
width = args[kWidth].as<uint32_t>();
if (args[kHeight].count())
height = args[kHeight].as<uint32_t>();
if (args[kDepth].count())
depth = args[kDepth].as<uint32_t>();
if (args[kLayers].count())
layers = args[kLayers].as<uint32_t>();
if (args[kLevels].count())
levels = args[kLevels].as<uint32_t>();
mipmapRuntime = args[kRuntimeMipmap].as<bool>();
mipmapGenerate = args[kGenerateMipmap].as<bool>();
if (args[kMipmapFilter].count()) {
static const std::unordered_set<std::string> filter_table{
"box",
"tent",
"bell",
"b-spline",
"mitchell",
"blackman",
"lanczos3",
"lanczos4",
"lanczos6",
"lanczos12",
"kaiser",
"gaussian",
"catmullrom",
"quadratic_interp",
"quadratic_approx",
"quadratic_mix",
};
mipmapFilter = to_lower_copy(args[kMipmapFilter].as<std::string>());
if (filter_table.count(*mipmapFilter) == 0)
report.fatal_usage("Invalid or unsupported mipmap filter specified as --mipmap-filter argument: \"{}\".", *mipmapFilter);
}
if (args[kMipmapFilterScale].count())
mipmapFilterScale = args[kMipmapFilterScale].as<float>();
if (args[kMipmapWrap].count()) {
static const std::unordered_map<std::string, basisu::Resampler::Boundary_Op> wrap_table{
{ "clamp", basisu::Resampler::Boundary_Op::BOUNDARY_CLAMP },
{ "wrap", basisu::Resampler::Boundary_Op::BOUNDARY_WRAP },
{ "reflect", basisu::Resampler::Boundary_Op::BOUNDARY_REFLECT },
};
const auto wrapStr = to_lower_copy(args[kMipmapWrap].as<std::string>());
const auto it = wrap_table.find(wrapStr);
if (it == wrap_table.end())
report.fatal_usage("Invalid or unsupported mipmap wrap mode specified as --mipmap-wrap argument: \"{}\".", wrapStr);
else
mipmapWrap = it->second;
}
if (args[kNormalize].count()) {
if (raw)
report.fatal_usage("Conflicting options: Option --normalize can't be used with --raw.");
normalize = true;
}
if (args[kSwizzle].count()) {
swizzle = to_lower_copy(args[kSwizzle].as<std::string>());
const auto errorFmt = "Invalid --swizzle value: \"{}\". The value must match the \"[rgba01]{{4}}\" regex.";
if (swizzle->size() != 4)
report.fatal_usage(errorFmt, *swizzle);
for (const auto c : *swizzle)
if (!contains("rgba01", c))
report.fatal_usage(errorFmt, *swizzle);
}
if (args[kInputSwizzle].count()) {
swizzleInput = to_lower_copy(args[kInputSwizzle].as<std::string>());
const auto errorFmt = "Invalid --input-swizzle value: \"{}\". The value must match the \"[rgba01]{{4}}\" regex.";
if (swizzleInput->size() != 4)
report.fatal_usage(errorFmt, *swizzleInput);
for (const auto c : *swizzleInput)
if (!contains("rgba01", c))
report.fatal_usage(errorFmt, *swizzleInput);
}
uint32_t numDimensions = 2;
if (args[kDepth].count())
numDimensions = 3;
else if (args[k1D].count())
numDimensions = 1;
assignTexcoordOrigin = parseTexcoordOrigin(args, numDimensions,
kAssignTexcoordOrigin, report);
convertTexcoordOrigin = parseTexcoordOrigin(args, numDimensions,
kConvertTexcoordOrigin, report);
if (args[kFormat].count()) {
const auto formatStr = args[kFormat].as<std::string>();
const auto parsedVkFormat = parseVkFormat(formatStr);
if (!parsedVkFormat)
report.fatal_usage("The requested format is invalid or unsupported: \"{}\".", formatStr);
vkFormat = *parsedVkFormat;
} else {
report.fatal_usage("Required option 'format' is missing.");
}
// List of formats that have supported format conversions
static const std::unordered_set<VkFormat> convertableFormats{
VK_FORMAT_R8_UNORM,
VK_FORMAT_R8_SRGB,
VK_FORMAT_R8G8_UNORM,
VK_FORMAT_R8G8_SRGB,
VK_FORMAT_R8G8B8_UNORM,
VK_FORMAT_R8G8B8_SRGB,
VK_FORMAT_B8G8R8_UNORM,
VK_FORMAT_B8G8R8_SRGB,
VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_R8G8B8A8_SRGB,
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_B8G8R8A8_SRGB,
VK_FORMAT_A8B8G8R8_UNORM_PACK32,
VK_FORMAT_A8B8G8R8_SRGB_PACK32,
VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
VK_FORMAT_R4G4_UNORM_PACK8,
VK_FORMAT_R5G6B5_UNORM_PACK16,
VK_FORMAT_B5G6R5_UNORM_PACK16,
VK_FORMAT_R4G4B4A4_UNORM_PACK16,
VK_FORMAT_B4G4R4A4_UNORM_PACK16,
VK_FORMAT_R5G5B5A1_UNORM_PACK16,
VK_FORMAT_B5G5R5A1_UNORM_PACK16,
VK_FORMAT_A1R5G5B5_UNORM_PACK16,
VK_FORMAT_A4R4G4B4_UNORM_PACK16,
VK_FORMAT_A4B4G4R4_UNORM_PACK16,
VK_FORMAT_R10X6_UNORM_PACK16,
VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
VK_FORMAT_R12X4_UNORM_PACK16,
VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
VK_FORMAT_R16_UNORM,
VK_FORMAT_R16G16_UNORM,
VK_FORMAT_R16G16B16_UNORM,
VK_FORMAT_R16G16B16A16_UNORM,
VK_FORMAT_A2R10G10B10_UNORM_PACK32,
VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_FORMAT_G8B8G8R8_422_UNORM,
VK_FORMAT_B8G8R8G8_422_UNORM,
VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
VK_FORMAT_G16B16G16R16_422_UNORM,
VK_FORMAT_B16G16R16G16_422_UNORM,
VK_FORMAT_R8_UINT,
VK_FORMAT_R8_SINT,
VK_FORMAT_R16_UINT,
VK_FORMAT_R16_SINT,
VK_FORMAT_R32_UINT,
VK_FORMAT_R8G8_UINT,
VK_FORMAT_R8G8_SINT,
VK_FORMAT_R16G16_UINT,
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R32G32_UINT,
VK_FORMAT_R8G8B8_UINT,
VK_FORMAT_R8G8B8_SINT,
VK_FORMAT_B8G8R8_UINT,
VK_FORMAT_B8G8R8_SINT,
VK_FORMAT_R16G16B16_UINT,
VK_FORMAT_R16G16B16_SINT,
VK_FORMAT_R32G32B32_UINT,
VK_FORMAT_R8G8B8A8_UINT,
VK_FORMAT_R8G8B8A8_SINT,
VK_FORMAT_B8G8R8A8_UINT,
VK_FORMAT_B8G8R8A8_SINT,
VK_FORMAT_A8B8G8R8_UINT_PACK32,
VK_FORMAT_A8B8G8R8_SINT_PACK32,
VK_FORMAT_R16G16B16A16_UINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R32G32B32A32_UINT,
VK_FORMAT_A2R10G10B10_UINT_PACK32,
VK_FORMAT_A2R10G10B10_SINT_PACK32,
VK_FORMAT_A2B10G10R10_SINT_PACK32,
VK_FORMAT_A2B10G10R10_UINT_PACK32,
VK_FORMAT_R16_SFLOAT,
VK_FORMAT_R16G16_SFLOAT,
VK_FORMAT_R16G16B16_SFLOAT,
VK_FORMAT_R16G16B16A16_SFLOAT,
VK_FORMAT_R32_SFLOAT,
VK_FORMAT_R32G32_SFLOAT,
VK_FORMAT_R32G32B32_SFLOAT,
VK_FORMAT_R32G32B32A32_SFLOAT,
VK_FORMAT_B10G11R11_UFLOAT_PACK32,
VK_FORMAT_E5B9G9R9_UFLOAT_PACK32,
VK_FORMAT_D16_UNORM,
VK_FORMAT_X8_D24_UNORM_PACK32,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_A8_UNORM_KHR,
VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR,
};
if (isProhibitedFormat(vkFormat))
report.fatal_usage("The requested {} format is prohibited in KTX files.", toString(vkFormat));
if (!raw && !convertableFormats.count(vkFormat))
report.fatal_usage("Unsupported format for non-raw create: {}.", toString(vkFormat));
if (raw) {
if (!width)
report.fatal_usage("Option --width is missing but is required for --raw texture creation.");
if (!height)
report.fatal_usage("Option --height is missing but is required for --raw texture creation.");
} else {
if (width)
report.warning("Option --width is ignored for non-raw texture creation.");
if (height)
report.warning("Option --height is ignored for non-raw texture creation.");
}
if (width == 0u)
report.fatal_usage("The --width cannot be 0.");
if (height == 0u)
report.fatal_usage("The --height cannot be 0.");
if (layers == 0u)
report.fatal_usage("The --layers cannot be 0.");
if (levels == 0u)
report.fatal_usage("The --levels cannot be 0.");
if (depth == 0u)
report.fatal_usage("The --depth cannot be 0.");
if (raw) {
const auto maxDimension = std::max(width.value_or(1), std::max(height.value_or(1), depth.value_or(1)));
const auto maxLevels = log2(maxDimension) + 1;
if (levels.value_or(1) > maxLevels)
report.fatal_usage("Requested {} levels is too many. With base size {}x{}x{} the texture can only have {} levels at most.",
levels.value_or(1), width.value_or(1), height.value_or(1), depth.value_or(1), maxLevels);
}
if (_1d && height && height != 1u)
report.fatal_usage("For --1d textures the --height must be 1.");
if (layers && depth)
report.fatal_usage("3D array texture creation is unsupported. --layers is {} and --depth is {}.",
*layers, *depth);
if (cubemap && depth)
report.fatal_usage("Cubemaps cannot have 3D textures. --depth is {}.", *depth);
if (mipmapRuntime && levels.value_or(1) > 1u)
report.fatal_usage("Conflicting options: --runtime-mipmap cannot be used with more than 1 --levels.");
if (mipmapGenerate && mipmapRuntime)
report.fatal_usage("Conflicting options: --generate-mipmap and --runtime-mipmap cannot be used together.");
if (mipmapGenerate && raw)
report.fatal_usage("Conflicting options: --generate-mipmap cannot be used with --raw.");
if (mipmapGenerate && depth)
report.fatal_usage("Mipmap generation for 3D textures is not supported: --generate-mipmap cannot be used with --depth.");
if (mipmapFilter && !mipmapGenerate)
report.fatal_usage("Option --mipmap-filter can only be used if --generate-mipmap is set.");
if (mipmapFilterScale && !mipmapGenerate)
report.fatal_usage("Option --mipmap-filter-scale can only be used if --generate-mipmap is set.");
if (mipmapWrap && !mipmapGenerate)
report.fatal_usage("Option --mipmap-wrap can only be used if --generate-mipmap is set.");
formatDesc = createFormatDescriptor(vkFormat, report);
convertTF = parseTransferFunction(args, kConvertTf, kConvertOetf, report);
assignTF = parseTransferFunction(args, kAssignTf, kAssignOetf, report);
convertPrimaries = parseColorPrimaries(args, kConvertPrimaries, report);
assignPrimaries = parseColorPrimaries(args, kAssignPrimaries, report);
if (convertPrimaries.has_value() && assignPrimaries == KHR_DF_PRIMARIES_UNSPECIFIED)
report.fatal_usage("Option --{} cannot be used when --{} is set to 'none'.",
kConvertPrimaries, kAssignPrimaries);
if (raw) {
if (convertTF.has_value())
report.fatal_usage("Option {} cannot be used with --{}.", kConvertTf, kRaw);
if (convertPrimaries.has_value())
report.fatal_usage("Option {} cannot be used with --{}.", kConvertPrimaries, kRaw);
if (convertTexcoordOrigin.has_value())
report.fatal_usage("Option {} cannot be used with --{}.", kConvertTexcoordOrigin, kRaw);
}
if (formatDesc.transfer() == KHR_DF_TRANSFER_SRGB) {
const auto error_message = "Invalid value \"{}\" to --{} for format \"{}\". Transfer function must be sRGB for sRGB formats.";
if (!convertTF.has_value() && assignTF.has_value()) {
switch (assignTF.value()) {
case KHR_DF_TRANSFER_UNSPECIFIED:
case KHR_DF_TRANSFER_SRGB:
// assign-tf must either not be specified or must be sRGB for an sRGB format
break;
default:
report.fatal_usage(error_message, args[kAssignTf].count() ? args[kAssignTf].as<std::string>() : args[kAssignOetf].as<std::string>(),
kAssignTf, args[kFormat].as<std::string>());
}
} else if (convertTF.has_value() && convertTF != KHR_DF_TRANSFER_SRGB) {
report.fatal_usage(error_message, args[kConvertTf].count() ? args[kConvertTf].as<std::string>() : args[kConvertOetf].as<std::string>(),
kConvertTf, args[kFormat].as<std::string>());
}
}
if (isFormatNotSRGBButHasSRGBVariant(vkFormat)) {
const auto error_message = "Invalid value \"{}\" to --{} for format \"{}\". Transfer function must not be sRGB for a non-sRGB VkFormat with sRGB variant.";
if (!convertTF.has_value() && assignTF.has_value() && assignTF == KHR_DF_TRANSFER_SRGB) {
report.fatal_usage(error_message, args[kAssignTf].count() ? args[kAssignTf].as<std::string>() : args[kAssignOetf].as<std::string>(),
kAssignTf, args[kFormat].as<std::string>());
} else if (convertTF.has_value() && convertTF == KHR_DF_TRANSFER_SRGB) {
report.fatal_usage(error_message, args[kConvertTf].count() ? args[kConvertTf].as<std::string>() : args[kConvertOetf].as<std::string>(),
kConvertTf, args[kFormat].as<std::string>());
}
}
if (args[kFailOnColorConversions].count())
failOnColorConversions = true;
if (args[kWarnOnColorConversions].count()) {
if (failOnColorConversions)
report.fatal_usage("The options --{} and --{} are mutually exclusive.",
kFailOnColorConversions, kWarnOnColorConversions);
warnOnColorConversions = true;
}
if (args[kFailOnOriginChanges].count())
failOnOriginChanges = true;
if (args[kWarnOnOriginChanges].count()) {
if (failOnOriginChanges)
report.fatal_usage("The options --{} and --{} are mutually exclusive.",
kFailOnOriginChanges, kWarnOnOriginChanges);
warnOnOriginChanges = true;
}
}
};
// -------------------------------------------------------------------------------------------------
/** @page ktx_create ktx create
@~English
Create a KTX2 file from various input files.
@section ktx_create_synopsis SYNOPSIS
ktx create [option...] @e input-file... @e output-file
@section ktx\_create\_description DESCRIPTION
@b ktx @b create can create, encode and supercompress a KTX2 file from the
input images specified as the @e input-file... arguments and save it as the
@e output-file. The last positional argument is treated as the @e output-file.
If the @e input-file is '-' the file will be read from the stdin.
If the @e output-path is '-' the output file will be written to the stdout.
Each @e input-file must be a valid EXR (.exr), PNG (.png) or Raw (.raw) file.
PNG files with luminance (L) or luminance + alpha (LA) data will be converted
to RGB as LLL and RGBA as LLLA before processing further.
The input file formats must be compatible with the requested KTX format enum
and must have at least the same level of precision and number of channels.
Any unused channel will be discarded silently.
The number of input-files specified must match the expected number of input
images based on the used options.
@section ktx\_create\_options OPTIONS
@subsection ktx\_create\_options\_general General Options
The following are available:
<dl>
<dt>\--format <enum></dt>
<dd>KTX format enum that specifies the data format for the images in the
created texture. The enum names match the VkFormat names without the
VK\_FORMAT\_ prefix. The VK\_FORMAT\_ prefix is ignored if present.
Case insensitive. Required.<br />
<br />
If the format is an ASTC format a texture object with the target
format @c R8G8B8_{SRGB,UNORM} or @c R8G8B8A8_{SRGB,UNORM} is
created then encoded to the specified ASTC format. The latter format
is chosen if alpha is present in the input. @c SRGB or @c UNORM is
chosen depending on the specified ASTC format. The ASTC-specific and
common encoder options listed @ref ktx_create_options_encoding
"below" become valid, otherwise they are ignored. This matches the
functionality of the @ref ktx_encode "ktx encode" command when an
ASTC format is specified.<br />
<br />
When used with @b \--encode it specifies the target format before
the encoding step. In this case it must be one of:
<ul>
<li>R8\_UNORM</li>
<li>R8\_SRGB</li>
<li>R8G8\_UNORM</li>
<li>R8G8\_SRGB</li>
<li>R8G8B8\_UNORM</li>
<li>R8G8B8\_SRGB</li>
<li>R8G8B8A8\_UNORM</li>
<li>R8G8B8A8\_SRGB</li>
</ul>
The format will be used to verify and load all input files into a
texture before performing any specified encoding.<br />
<br />
In a change from previous versions no automatic color conversions
are performed. The transfer function of the input images,
potentially modified by @b \--assign-tf or @b \--convert-tf options,
must match that of the chosen VkFormat according to the rules given
in @ref ktx\_create\_tf\_handling below.
</dd>
<dt>\--encode basis-lz | uastc</dt>
<dd>Encode the texture with the specified codec before saving it.
This option matches the functionality of the @ref ktx_encode
"ktx encode" command. With each choice, the specific and common
encoder options listed @ref ktx_create_options_encoding "below"
become valid, otherwise they are ignored. Case-insensitive.</dd>
@snippet{doc} ktx/encode_utils_basis.h command options_basis_encoders
<dt>\--1d</dt>
<dd>Create a 1D texture. If not set the texture will be a 2D or
3D texture.</dd>
<dt>\--cubemap</dt>
<dd>Create a cubemap texture. If not set the texture will be a 2D or
3D texture.</dd>
<dt>\--raw</dt>
<dd>Create from raw image data.</dd>
<dt>\--width</dt>
<dd>Base level width in pixels.</dd>
<dt>\--height</dt>
<dd>Base level height in pixels.</dd>
<dt>\--depth</dt>
<dd>Base level depth in pixels.
If set the texture will be a 3D texture.</dd>
<dt>\--layers</dt>
<dd>Number of layers.
If set the texture will be an array texture.</dd>
<dt>\--runtime-mipmap</dt>
<dd>Runtime mipmap generation mode.
Sets up the texture to request the mipmaps to be generated by the
client application at runtime.</dd>
<dt>\--generate-mipmap</dt>
<dd>Causes mipmaps to be generated during texture creation.
If @b \--levels is not specified the maximum possible mip level will
be generated. This option is mutually exclusive with
--runtime-mipmap and cannot be used with SINT, UINT or 3D textures.
When set it enables the use of the following 'Generate Mipmap'
options.
<dl>
<dt>\--mipmap-filter <filter></dt>
<dd>Specifies the filter to use when generating the mipmaps.
Case insensitive.<br />
Possible options are:
box | tent | bell | b-spline | mitchell | blackman | lanczos3 |
lanczos4 | lanczos6 | lanczos12 | kaiser | gaussian |
catmullrom | quadratic_interp | quadratic_approx |
quadratic_mix.
Defaults to lanczos4.</dd>
<dt>\--mipmap-filter-scale <float></dt>
<dd>The filter scale to use.
Defaults to 1.0.</dd>
<dt>\--mipmap-wrap <mode></dt>
<dd>Specify how to sample pixels near the image boundaries.
Case insensitive.<br />
Possible options are:
wrap | reflect | clamp.
Defaults to clamp.</dd>
</dl>
Avoid mipmap generation if the Output TF (see @ref ktx\_create\_tf\_handling
below) is non-linear and is not sRGB.
</dd>
<dt>\--normalize</dt>
<dd>Normalize input normals to have a unit length. Only valid for
linear normal textures with 2 or more components. For 2-component
inputs 2D unit normals are calculated. Do not use these 2D unit
normals to generate X+Y normals with @b --normal-mode. For 4-component
inputs a 3D unit normal is calculated. 1.0 is used for the value of
the 4th component. Cannot be used with @b \--raw.</dd>
<dt>\--swizzle [rgba01]{4}</dt>
<dd>KTX swizzle metadata.</dd>
<dt>\--input-swizzle [rgba01]{4}</dt>
<dd>Pre-swizzle input channels.</dd>
<dt>\--assign-tf <transfer function></dt>
<dd>Force the created texture to have the specified transfer function,
ignoring the transfer function of the input file(s). Possible
options match the khr_df_transfer_e enumerators without the
KHR_DF_TRANSFER_ prefix except that hlg_unnormalized_oetf is not
allowed. The KHR_DF_TRANSFER_ prefix is ignored if present. Case
insensitive. The options are:
linear | srgb | srgb_eotf | scrgb | scrgb_eotf | itu | itu_oetf |
bt601 | bt601_oetf | bt709 | bt709_oetf | bt2020 | bt2020_oetf |
smpte170m | smpte170m_oetf | smpte170m_eotf | ntsc | ntsc_eotf |
slog | slog_oetf | slog2 | slog2_oetf | bt1886 | bt1886_eotf |
hlg_oetf | hlg_eotf | pq_oetf | pg_eotf | dcip3 | dcip3_eotf |
pal_oetf | pal625_eotf | st240 | st240_oetf | st240_eotf | acescc |
acescc_oetf | acescct | acescct_oetf | abobergb | adobergb_eotf
See @ref ktx_create_tf_handling below for important information.
</dd>
<dt>\--assign-oetf <transfer function></dt>
<dd>Deprecated and will be removed. Use @b \--assign-tf instead.</dd>
<dt>\--assign-primaries <primaries></dt>
<dd>Force the created texture to have the specified color primaries,
ignoring the color primaries of the input file(s). Possible options
match the khr_df_primaries_e enumerators without the
KHR_DF_PRIMARIES_ prefix. The KHR_DF_PRIMARIES_ prefix is ignored
if present. Case insensitive. The options are:
none | bt709 | srgb | bt601_ebu | bt601_smpte | bt2020 | ciexyz |
aces | acescc | ntsc1953 | pal525 | displayp3 | adobergb.
@note @c bt601-ebu and @c bt601-smpte, supported in previous
releases, have been replaced with names consistent with
khr_df_primaries_e.
</dd>
<dt>\--assign-texcoord-origin <corner></dt>
<dd>Force the created texture to indicate that the texture coordinate
origin s=0, t=0 is at the specified @em corner of the logical image.
Case insensitive. Possible options are top-left | bottom-left.
-front | -back can be appended and one of these is required when
@b \--depth is specified. Must be top-left if @b \--cubemap is
specified. Absent @b —convert-texcoord-origin, the effect of this
option is to cause @e KTXorientation metadata indicating the
specified origin to be written to the output file. Example values
are "rd" (top-left) and "ru" (bottom-left) or, when @b \--depth is
specified, "rdi" (top-left-front) and "rui" (bottom-left-front).
</dd>
<dt>\--convert-tf <transfer function></dt>
<dd>Convert the input image(s) to the specified transfer function, if
different from the transfer function of the input file(s). If both
this and @b \--assign-tf are specified, conversion will be
performed from the assigned transfer function to the transfer
function specified by this option, if different. Cannot be used with
@b \--raw. Case insensitive.
The options are: linear | srgb. The following srgb aliases are
also supported: srgb_eotf | scrgb | scrgb_eotf.
See @ref ktx_create_tf_handling below for more information.
</dd>
<dt>\--convert-oetf <transfer function></dt>
<dd>Deprecated and will be removed. Use @b \--convert-tf instead.</dd>
<dt>\--convert-primaries <primaries></dt>
<dd>Convert the input image(s) to the specified color primaries, if
different from the color primaries of the input file(s) or the one
specified by @b \--assign-primaries. If both this and
@b \--assign-primaries are specified, conversion will be performed
from the assigned primaries to the primaries specified by this
option, if different. This option is not allowed to be specified
when @b \--assign-primaries is set to 'none'.
Cannot be used with @b \--raw. Possible options match the
khr_df_primaries_e enumerators without the KHR_DF_PRIMARIES_
prefix. The KHR_DF_PRIMARIES_ prefix is ignored if present.
Case insensitive. The options are:
bt709 | srgb | bt601_ebu | bt601_smpte | bt2020 | ciexyz | aces | acescc | ntsc1953 |
pal525 | displayp3 | adobergb
@note @c bt601-ebu and @c bt601-smpte, supported in previous
releases, have been replaced with names consistent with
khr_df_primaries_e.
<dt>\--convert-texcoord-origin <corner></dt>
<dd>Convert the input image(s) so the texture coordinate origin s=0,
t=0, is at the specified @em corner of the logical image. If both
this and @b \--assign-texcoord-origin are specified, conversion will
be performed from the assigned origin to the origin specified by
this option, if different. The default for images in KTX files is
top-left which corresponds to the origin in most image file
formats. Cannot be used with @b \--raw. Case insensitive.
Possible options are: top-left | bottom-left. -front | -back can be