Skip to content

Commit

Permalink
Merge pull request zeux#290 from zeux/gltf-flipy
Browse files Browse the repository at this point in the history
gltfpack: Implement support for texture flipping
  • Loading branch information
zeux authored May 22, 2021
2 parents f5d83e8 + 38bf28b commit 0d2ba6e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 49 deletions.
1 change: 0 additions & 1 deletion gltf/basistoktx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ std::string basisToKtx(const std::string& data, bool srgb, bool uastc)

assert(basis_header.m_tex_format == uint32_t(uastc ? basist::cUASTC4x4 : basist::cETC1S));
assert(!(basis_header.m_flags & basist::cBASISHeaderFlagETC1S) == uastc);
assert(!(basis_header.m_flags & basist::cBASISHeaderFlagYFlipped));
assert(basis_header.m_tex_type == basist::cBASISTexType2D);

if (uastc)
Expand Down
43 changes: 30 additions & 13 deletions gltf/gltfpack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,12 @@ Settings defaults()
return settings;
}

template <typename T>
T clamp(T v, T min, T max)
{
return v < min ? min : v > max ? max : v;
}

int main(int argc, char** argv)
{
meshopt_encodeIndexVersion(1);
Expand All @@ -1090,35 +1096,35 @@ int main(int argc, char** argv)

if (strcmp(arg, "-vp") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.pos_bits = atoi(argv[++i]);
settings.pos_bits = clamp(atoi(argv[++i]), 1, 16);
}
else if (strcmp(arg, "-vt") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.tex_bits = atoi(argv[++i]);
settings.tex_bits = clamp(atoi(argv[++i]), 1, 16);
}
else if (strcmp(arg, "-vn") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.nrm_bits = atoi(argv[++i]);
settings.nrm_bits = clamp(atoi(argv[++i]), 1, 16);
}
else if (strcmp(arg, "-vc") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.col_bits = atoi(argv[++i]);
settings.col_bits = clamp(atoi(argv[++i]), 1, 16);
}
else if (strcmp(arg, "-at") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.trn_bits = atoi(argv[++i]);
settings.trn_bits = clamp(atoi(argv[++i]), 1, 24);
}
else if (strcmp(arg, "-ar") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.rot_bits = atoi(argv[++i]);
settings.rot_bits = clamp(atoi(argv[++i]), 4, 16);
}
else if (strcmp(arg, "-as") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.scl_bits = atoi(argv[++i]);
settings.scl_bits = clamp(atoi(argv[++i]), 1, 24);
}
else if (strcmp(arg, "-af") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.anim_freq = atoi(argv[++i]);
settings.anim_freq = clamp(atoi(argv[++i]), 1, 100);
}
else if (strcmp(arg, "-ac") == 0)
{
Expand Down Expand Up @@ -1146,7 +1152,7 @@ int main(int argc, char** argv)
}
else if (strcmp(arg, "-si") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.simplify_threshold = float(atof(argv[++i]));
settings.simplify_threshold = clamp(float(atof(argv[++i])), 0.f, 1.f);
}
else if (strcmp(arg, "-sa") == 0)
{
Expand All @@ -1155,11 +1161,11 @@ int main(int argc, char** argv)
#ifndef NDEBUG
else if (strcmp(arg, "-sd") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.simplify_debug = float(atof(argv[++i]));
settings.simplify_debug = clamp(float(atof(argv[++i])), 0.f, 1.f);
}
else if (strcmp(arg, "-md") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.meshlet_debug = atoi(argv[++i]);
settings.meshlet_debug = clamp(atoi(argv[++i]), 3, 255);
}
#endif
else if (strcmp(arg, "-tu") == 0)
Expand All @@ -1173,16 +1179,20 @@ int main(int argc, char** argv)
}
else if (strcmp(arg, "-tq") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.texture_quality = atoi(argv[++i]);
settings.texture_quality = clamp(atoi(argv[++i]), 1, 10);
}
else if (strcmp(arg, "-ts") == 0 && i + 1 < argc && isdigit(argv[i + 1][0]))
{
settings.texture_scale = float(atof(argv[++i]));
settings.texture_scale = clamp(float(atof(argv[++i])), 0.f, 1.f);
}
else if (strcmp(arg, "-tp") == 0)
{
settings.texture_pow2 = true;
}
else if (strcmp(arg, "-tfy") == 0)
{
settings.texture_flipy = true;
}
else if (strcmp(arg, "-te") == 0)
{
fprintf(stderr, "Warning: -te is deprecated and will be removed in the future; gltfpack now automatically embeds textures into GLB files\n");
Expand Down Expand Up @@ -1286,6 +1296,7 @@ int main(int argc, char** argv)
fprintf(stderr, "\t-tq N: set texture encoding quality (default: 8; N should be between 1 and 10\n");
fprintf(stderr, "\t-ts R: scale texture dimensions by the ratio R (default: 1; R should be between 0 and 1)\n");
fprintf(stderr, "\t-tp: resize textures to nearest power of 2 to conform to WebGL1 restrictions\n");
fprintf(stderr, "\t-tfy: flip textures along Y axis during BasisU supercompression\n");
fprintf(stderr, "\nSimplification:\n");
fprintf(stderr, "\t-si R: simplify meshes to achieve the ratio R (default: 1; R should be between 0 and 1)\n");
fprintf(stderr, "\t-sa: aggressively simplify to the target ratio disregarding quality\n");
Expand Down Expand Up @@ -1339,6 +1350,12 @@ int main(int argc, char** argv)
return 1;
}

if (settings.texture_flipy && !settings.texture_ktx2)
{
fprintf(stderr, "Option -tfy is only supported when -tc is set as well\n");
return 1;
}

return gltfpack(input, output, report, settings);
}

Expand Down
6 changes: 3 additions & 3 deletions gltf/gltfpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ struct Settings
int texture_quality;
float texture_scale;
bool texture_pow2;
bool texture_flipy;

bool quantize;

Expand Down Expand Up @@ -272,11 +273,10 @@ void analyzeMaterials(cgltf_data* data, std::vector<MaterialInfo>& materials, st

const char* inferMimeType(const char* path);
bool checkBasis(bool verbose);
bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose);
bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, const ImageInfo& info, const Settings& settings);
std::string basisToKtx(const std::string& data, bool srgb, bool uastc);
bool checkKtx(bool verbose);
bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose);

bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, const ImageInfo& info, const Settings& settings);
void markScenes(cgltf_data* data, std::vector<NodeInfo>& nodes);
void markAnimated(cgltf_data* data, std::vector<NodeInfo>& nodes, const std::vector<Animation>& animations);
void markNeededNodes(cgltf_data* data, std::vector<NodeInfo>& nodes, const std::vector<Mesh>& meshes, const std::vector<Animation>& animations, const Settings& settings);
Expand Down
62 changes: 33 additions & 29 deletions gltf/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,9 @@ bool checkBasis(bool verbose)
return rc == 0;
}

bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose)
bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, const ImageInfo& info, const Settings& settings)
{
(void)scale;
(void)pow2;

// TODO: Support texture_scale and texture_pow2 via new -resample switch from https://github.com/BinomialLLC/basis_universal/pull/226
TempFile temp_input(mimeExtension(mime_type));
TempFile temp_output(".basis");

Expand All @@ -122,35 +120,38 @@ bool encodeBasis(const std::string& data, const char* mime_type, std::string& re

std::string cmd = getExecutable("basisu", "BASISU_PATH");

const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];
const BasisSettings& bs = kBasisSettings[settings.texture_quality - 1];

cmd += " -mipmap";

if (normal_map)
if (settings.texture_flipy)
cmd += " -y_flip";

if (info.normal_map)
{
cmd += " -normal_map";
// for optimal quality we should specify seperate_rg_to_color_alpha but this requires renderer awareness
}
else if (!srgb)
else if (!info.srgb)
{
cmd += " -linear";
}

if (uastc)
if (settings.texture_uastc)
{
char settings[128];
sprintf(settings, " -uastc_level %d -uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);
char cs[128];
sprintf(cs, " -uastc_level %d -uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

cmd += " -uastc";
cmd += settings;
cmd += cs;
cmd += " -uastc_rdo_d 1024";
}
else
{
char settings[128];
sprintf(settings, " -comp_level %d -q %d", bs.etc1s_l, bs.etc1s_q);
char cs[128];
sprintf(cs, " -comp_level %d -q %d", bs.etc1s_l, bs.etc1s_q);

cmd += settings;
cmd += cs;
}

cmd += " -file ";
Expand All @@ -159,7 +160,7 @@ bool encodeBasis(const std::string& data, const char* mime_type, std::string& re
cmd += temp_output.path;

int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ false);
if (verbose)
if (settings.verbose > 1)
printf("%s => %d\n", cmd.c_str(), rc);

return rc == 0 && readFile(temp_output.path.c_str(), result);
Expand Down Expand Up @@ -279,7 +280,7 @@ static int roundBlock(int value, bool pow2)
return (value + 3) & ~3;
}

bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose)
bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, const ImageInfo& info, const Settings& settings)
{
int width = 0, height = 0;
if (!getDimensions(data, mime_type, width, height))
Expand All @@ -293,15 +294,15 @@ bool encodeKtx(const std::string& data, const char* mime_type, std::string& resu

std::string cmd = getExecutable("toktx", "TOKTX_PATH");

const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];
const BasisSettings& bs = kBasisSettings[settings.texture_quality - 1];

cmd += " --t2";
cmd += " --2d";
cmd += " --genmipmap";
cmd += " --nowarn";

int newWidth = roundBlock(int(width * scale), pow2);
int newHeight = roundBlock(int(height * scale), pow2);
int newWidth = roundBlock(int(width * settings.texture_scale), settings.texture_pow2);
int newHeight = roundBlock(int(height * settings.texture_scale), settings.texture_pow2);

if (newWidth != width || newHeight != height)
{
Expand All @@ -310,30 +311,33 @@ bool encodeKtx(const std::string& data, const char* mime_type, std::string& resu
cmd += wh;
}

if (uastc)
if (settings.texture_flipy)
cmd += " --lower_left_maps_to_s0t0";

if (settings.texture_uastc)
{
char settings[128];
sprintf(settings, " %d --uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);
char cs[128];
sprintf(cs, " %d --uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

cmd += " --uastc";
cmd += settings;
cmd += cs;
cmd += " --uastc_rdo_d 1024";
cmd += " --zcmp 9";
}
else
{
char settings[128];
sprintf(settings, " --clevel %d --qlevel %d", bs.etc1s_l, bs.etc1s_q);
char cs[128];
sprintf(cs, " --clevel %d --qlevel %d", bs.etc1s_l, bs.etc1s_q);

cmd += " --bcmp";
cmd += settings;
cmd += cs;

// for optimal quality we should specify separate_rg_to_color_alpha but this requires renderer awareness
if (normal_map)
if (info.normal_map)
cmd += " --normal_map";
}

if (srgb)
if (info.srgb)
cmd += " --srgb";
else
cmd += " --linear";
Expand All @@ -344,7 +348,7 @@ bool encodeKtx(const std::string& data, const char* mime_type, std::string& resu
cmd += temp_input.path;

int rc = execute(cmd.c_str(), /* ignore_stdout= */ false, /* ignore_stderr= */ false);
if (verbose)
if (settings.verbose > 1)
printf("%s => %d\n", cmd.c_str(), rc);

return rc == 0 && readFile(temp_output.path.c_str(), result);
Expand Down
6 changes: 3 additions & 3 deletions gltf/write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ void writeImage(std::string& json, std::vector<BufferView>& views, const cgltf_i
if (image.mime_type)
mime_type = image.mime_type;

bool (*encodeImage)(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose) =
bool (*encodeImage)(const std::string& data, const char* mime_type, std::string& result, const ImageInfo& info, const Settings& settings) =
settings.texture_toktx ? encodeKtx : encodeBasis;

if (!img_data.empty())
Expand All @@ -839,7 +839,7 @@ void writeImage(std::string& json, std::vector<BufferView>& views, const cgltf_i
{
std::string encoded;

if (encodeImage(img_data, mime_type.c_str(), encoded, info.normal_map, info.srgb, settings.texture_quality, settings.texture_scale, settings.texture_pow2, settings.texture_uastc, settings.verbose > 1))
if (encodeImage(img_data, mime_type.c_str(), encoded, info, settings))
{
if (!settings.texture_toktx)
encoded = basisToKtx(encoded, info.srgb, settings.texture_uastc);
Expand Down Expand Up @@ -868,7 +868,7 @@ void writeImage(std::string& json, std::vector<BufferView>& views, const cgltf_i
{
std::string encoded;

if (encodeImage(img_data, mime_type.c_str(), encoded, info.normal_map, info.srgb, settings.texture_quality, settings.texture_scale, settings.texture_pow2, settings.texture_uastc, settings.verbose > 1))
if (encodeImage(img_data, mime_type.c_str(), encoded, info, settings))
{
if (!settings.texture_toktx)
encoded = basisToKtx(encoded, info.srgb, settings.texture_uastc);
Expand Down

0 comments on commit 0d2ba6e

Please sign in to comment.