texassemble: command syntax with strip/cross, -srgb, -y, -wrap, -mirror, -alpha switches

This commit is contained in:
Chuck Walbourn 2016-09-24 01:06:54 -07:00
parent 97fa22b8ae
commit df72538e93

View File

@ -32,21 +32,37 @@
using namespace DirectX; using namespace DirectX;
enum COMMANDS
{
CMD_CUBE = 1,
CMD_VOLUME,
CMD_ARRAY,
CMD_CUBEARRAY,
CMD_H_CROSS,
CMD_V_CROSS,
CMD_H_STRIP,
CMD_V_STRIP,
CMD_MAX
};
enum OPTIONS enum OPTIONS
{ {
OPT_RECURSIVE = 1, OPT_RECURSIVE = 1,
OPT_CUBE,
OPT_VOLUME,
OPT_ARRAY,
OPT_CUBEARRAY,
OPT_WIDTH, OPT_WIDTH,
OPT_HEIGHT, OPT_HEIGHT,
OPT_FORMAT, OPT_FORMAT,
OPT_FILTER, OPT_FILTER,
OPT_SRGBI,
OPT_SRGBO,
OPT_SRGB,
OPT_OUTPUTFILE, OPT_OUTPUTFILE,
OPT_OVERWRITE,
OPT_USE_DX10, OPT_USE_DX10,
OPT_NOLOGO, OPT_NOLOGO,
OPT_SEPALPHA, OPT_SEPALPHA,
OPT_DEMUL_ALPHA,
OPT_TA_WRAP,
OPT_TA_MIRROR,
OPT_MAX OPT_MAX
}; };
@ -67,21 +83,37 @@ struct SValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
SValue g_pCommands[] =
{
{ L"cube", CMD_CUBE },
{ L"volume", CMD_VOLUME },
{ L"array", CMD_ARRAY },
{ L"cubearray", CMD_CUBEARRAY },
{ L"h-cross", CMD_H_CROSS },
{ L"v-cross", CMD_V_CROSS },
{ L"h-strip", CMD_H_STRIP },
{ L"v-strip", CMD_V_STRIP },
{ nullptr, 0 }
};
SValue g_pOptions[] = SValue g_pOptions[] =
{ {
{ L"r", OPT_RECURSIVE }, { L"r", OPT_RECURSIVE },
{ L"cube", OPT_CUBE },
{ L"volume", OPT_VOLUME },
{ L"array", OPT_ARRAY },
{ L"cubearray", OPT_CUBEARRAY },
{ L"w", OPT_WIDTH }, { L"w", OPT_WIDTH },
{ L"h", OPT_HEIGHT }, { L"h", OPT_HEIGHT },
{ L"f", OPT_FORMAT }, { L"f", OPT_FORMAT },
{ L"if", OPT_FILTER }, { L"if", OPT_FILTER },
{ L"srgbi", OPT_SRGBI },
{ L"srgbo", OPT_SRGBO },
{ L"srgb", OPT_SRGB },
{ L"o", OPT_OUTPUTFILE }, { L"o", OPT_OUTPUTFILE },
{ L"y", OPT_OVERWRITE },
{ L"dx10", OPT_USE_DX10 }, { L"dx10", OPT_USE_DX10 },
{ L"nologo", OPT_NOLOGO }, { L"nologo", OPT_NOLOGO },
{ L"sepalpha", OPT_SEPALPHA }, { L"sepalpha", OPT_SEPALPHA },
{ L"alpha", OPT_DEMUL_ALPHA },
{ L"wrap", OPT_TA_WRAP },
{ L"mirror", OPT_TA_MIRROR },
{ nullptr, 0 } { nullptr, 0 }
}; };
@ -149,6 +181,13 @@ SValue g_pFormats[] =
DEFFMT(B8G8R8X8_UNORM_SRGB), DEFFMT(B8G8R8X8_UNORM_SRGB),
// DXGI 1.2 formats // DXGI 1.2 formats
DEFFMT(AYUV),
DEFFMT(Y410),
DEFFMT(Y416),
DEFFMT(YUY2),
DEFFMT(Y210),
DEFFMT(Y216),
// No support for legacy paletted video formats (AI44, IA44, P8, A8P8)
DEFFMT(B4G4R4A4_UNORM), DEFFMT(B4G4R4A4_UNORM),
{ nullptr, DXGI_FORMAT_UNKNOWN } { nullptr, DXGI_FORMAT_UNKNOWN }
@ -177,6 +216,27 @@ SValue g_pFilters[] =
{ nullptr, TEX_FILTER_DEFAULT } { nullptr, TEX_FILTER_DEFAULT }
}; };
#define CODEC_DDS 0xFFFF0001
#define CODEC_TGA 0xFFFF0002
#define CODEC_HDR 0xFFFF0005
SValue g_pExtFileTypes[] =
{
{ L".BMP", WIC_CODEC_BMP },
{ L".JPG", WIC_CODEC_JPEG },
{ L".JPEG", WIC_CODEC_JPEG },
{ L".PNG", WIC_CODEC_PNG },
{ L".DDS", CODEC_DDS },
{ L".TGA", CODEC_TGA },
{ L".HDR", CODEC_HDR },
{ L".TIF", WIC_CODEC_TIFF },
{ L".TIFF", WIC_CODEC_TIFF },
{ L".WDP", WIC_CODEC_WMP },
{ L".HDP", WIC_CODEC_WMP },
{ L".JXR", WIC_CODEC_WMP },
{ nullptr, CODEC_DDS }
};
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -345,6 +405,19 @@ namespace
break; break;
} }
switch (info.GetAlphaMode())
{
case TEX_ALPHA_MODE_OPAQUE:
wprintf(L" \x0e0:Opaque");
break;
case TEX_ALPHA_MODE_PREMULTIPLIED:
wprintf(L" \x0e0:PM");
break;
case TEX_ALPHA_MODE_STRAIGHT:
wprintf(L" \x0e0:NonPM");
break;
}
wprintf(L")"); wprintf(L")");
} }
@ -385,28 +458,31 @@ namespace
{ {
PrintLogo(); PrintLogo();
wprintf(L"Usage: texassemble [-cube | - volume | -array | -cubearray] <options> <files>\n"); wprintf(L"Usage: texassemble <command> <options> <files>\n\n");
wprintf(L"\n"); wprintf(L" cube create cubemap\n");
wprintf(L" volume create volume map\n");
wprintf(L" array create texture array\n");
wprintf(L" cubearray create cubemap array\n");
wprintf(L" h-cross or v-cross create a cross image from a cubemap\n");
wprintf(L" h-strip or v-strip create a strip image from a cubemap\n\n");
wprintf(L" -r wildcard filename search is recursive\n"); wprintf(L" -r wildcard filename search is recursive\n");
wprintf(L" -cube create cubemap\n");
wprintf(L" -volume create volume map\n");
wprintf(L" -array create texture array\n");
wprintf(L" -cubearray create cubemap array\n");
wprintf(L" -w <n> width\n"); wprintf(L" -w <n> width\n");
wprintf(L" -h <n> height\n"); wprintf(L" -h <n> height\n");
wprintf(L" -f <format> format\n"); wprintf(L" -f <format> format\n");
wprintf(L" -if <filter> image filtering\n"); wprintf(L" -if <filter> image filtering\n");
wprintf(L" -srgb{i|o} sRGB {input, output}\n");
wprintf(L" -o <filename> output filename\n"); wprintf(L" -o <filename> output filename\n");
wprintf(L" -y overwrite existing output file (if any)\n");
wprintf(L" -sepalpha resize alpha channel separately from color channels\n"); wprintf(L" -sepalpha resize alpha channel separately from color channels\n");
wprintf(L" -wrap, -mirror texture addressing mode (wrap, mirror, or clamp)\n");
wprintf(L" -alpha convert premultiplied alpha to straight alpha\n");
wprintf(L" -dx10 Force use of 'DX10' extended header\n"); wprintf(L" -dx10 Force use of 'DX10' extended header\n");
wprintf(L" -nologo suppress copyright message\n"); wprintf(L" -nologo suppress copyright message\n");
wprintf(L"\n"); wprintf(L"\n <format>: ");
wprintf(L" <format>: ");
PrintList(13, g_pFormats); PrintList(13, g_pFormats);
wprintf(L"\n"); wprintf(L"\n <filter>: ");
wprintf(L" <filter>: ");
PrintList(13, g_pFilters); PrintList(13, g_pFilters);
} }
} }
@ -425,7 +501,9 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
DWORD dwFilter = TEX_FILTER_DEFAULT; DWORD dwFilter = TEX_FILTER_DEFAULT;
DWORD dwSRGB = 0;
DWORD dwFilterOpts = 0; DWORD dwFilterOpts = 0;
DWORD CrossFileType = WIC_CODEC_BMP;
wchar_t szOutputFile[MAX_PATH] = { 0 }; wchar_t szOutputFile[MAX_PATH] = { 0 };
@ -441,7 +519,31 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
DWORD dwOptions = 0; DWORD dwOptions = 0;
std::list<SConversion> conversion; std::list<SConversion> conversion;
for (int iArg = 1; iArg < argc; iArg++) if (argc < 2)
{
PrintUsage();
return 0;
}
DWORD dwCommand = LookupByName(argv[1], g_pCommands);
switch (dwCommand)
{
case CMD_CUBE:
case CMD_VOLUME:
case CMD_ARRAY:
case CMD_CUBEARRAY:
case CMD_H_CROSS:
case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
break;
default:
wprintf(L"Must use one of: cube, volume, array, cubearray,\n h-cross, v-cross, h-strip, or v-strip\n\n");
return 1;
}
for (int iArg = 2; iArg < argc; iArg++)
{ {
PWSTR pArg = argv[iArg]; PWSTR pArg = argv[iArg];
@ -522,12 +624,69 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
break; break;
case OPT_SRGBI:
dwSRGB |= TEX_FILTER_SRGB_IN;
break;
case OPT_SRGBO:
dwSRGB |= TEX_FILTER_SRGB_OUT;
break;
case OPT_SRGB:
dwSRGB |= TEX_FILTER_SRGB;
break;
case OPT_SEPALPHA: case OPT_SEPALPHA:
dwFilterOpts |= TEX_FILTER_SEPARATE_ALPHA; dwFilterOpts |= TEX_FILTER_SEPARATE_ALPHA;
break; break;
case OPT_OUTPUTFILE: case OPT_OUTPUTFILE:
{
wcscpy_s(szOutputFile, MAX_PATH, pValue); wcscpy_s(szOutputFile, MAX_PATH, pValue);
wchar_t ext[_MAX_EXT];
_wsplitpath_s(szOutputFile, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT);
wprintf(L"Ext = %ls\n", ext);
CrossFileType = LookupByName(ext, g_pExtFileTypes);
switch (dwCommand)
{
case CMD_H_CROSS:
case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
break;
default:
if (CrossFileType != CODEC_DDS)
{
wprintf(L"Assembled output file must be a dds\n");
return 1;
}
}
break;
}
case OPT_TA_WRAP:
if (dwFilterOpts & TEX_FILTER_MIRROR)
{
wprintf(L"Can't use -wrap and -mirror at same time\n\n");
PrintUsage();
return 1;
}
dwFilterOpts |= TEX_FILTER_WRAP;
break;
case OPT_TA_MIRROR:
if (dwFilterOpts & TEX_FILTER_WRAP)
{
wprintf(L"Can't use -wrap and -mirror at same time\n\n");
PrintUsage();
return 1;
}
dwFilterOpts |= TEX_FILTER_MIRROR;
break; break;
} }
} }
@ -556,22 +715,23 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 0; return 0;
} }
switch (dwOptions & ((1 << OPT_CUBE) | (1 << OPT_VOLUME) | (1 << OPT_ARRAY) | (1 << OPT_CUBEARRAY)))
{
case (1 << OPT_VOLUME):
case (1 << OPT_ARRAY):
case (1 << OPT_CUBE):
case (1 << OPT_CUBEARRAY):
break;
default:
wprintf(L"Must use one of: -cube, -volume, -array, or -cubearray\n\n");
return 1;
}
if (~dwOptions & (1 << OPT_NOLOGO)) if (~dwOptions & (1 << OPT_NOLOGO))
PrintLogo(); PrintLogo();
switch (dwCommand)
{
case CMD_H_CROSS:
case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
if (conversion.size() > 1)
{
wprintf(L"ERROR: cross/strip output only accepts 1 input file\n");
return 1;
}
break;
}
// Convert images // Convert images
size_t images = 0; size_t images = 0;
@ -588,13 +748,25 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
else if (!*szOutputFile) else if (!*szOutputFile)
{ {
if (_wcsicmp(ext, L".dds") == 0) switch (dwCommand)
{ {
wprintf(L"ERROR: Need to specify output file via -o\n"); case CMD_H_CROSS:
return 1; case CMD_V_CROSS:
} case CMD_H_STRIP:
case CMD_V_STRIP:
_wmakepath_s(szOutputFile, nullptr, nullptr, fname, L".bmp");
break;
_wmakepath_s(szOutputFile, nullptr, nullptr, fname, L".dds"); default:
if (_wcsicmp(ext, L".dds") == 0)
{
wprintf(L"ERROR: Need to specify output file via -o\n");
return 1;
}
_wmakepath_s(szOutputFile, nullptr, nullptr, fname, L".dds");
break;
}
} }
wprintf(L"reading %ls", pConv->szSrc); wprintf(L"reading %ls", pConv->szSrc);
@ -608,57 +780,92 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 1; return 1;
} }
if (_wcsicmp(ext, L".dds") == 0) switch (dwCommand)
{ {
hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image.get()); case CMD_H_CROSS:
if (FAILED(hr)) case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
if (_wcsicmp(ext, L".dds") == 0)
{ {
wprintf(L" FAILED (%x)\n", hr); hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image.get());
return 1; if (FAILED(hr))
} {
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
if (info.depth > 1 if (!info.IsCubemap())
|| info.mipLevels > 1 {
|| info.IsCubemap()) wprintf(L"\nERROR: Input must be a cubemap\n");
return 1;
}
else if (info.arraySize != 6)
{
wprintf(L"\nWARNING: Only the first cubemap in an array is written out as a cross/strip\n");
}
}
else
{ {
wprintf(L"\nERROR: Can't assemble complex surfaces\n"); wprintf(L"\nERROR: Input must be a dds of a cubemap\n");
return 1; return 1;
} }
} break;
else if (_wcsicmp(ext, L".tga") == 0)
{
hr = LoadFromTGAFile(pConv->szSrc, &info, *image.get());
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
}
else if (_wcsicmp(ext, L".hdr") == 0)
{
hr = LoadFromHDRFile(pConv->szSrc, &info, *image.get());
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
}
else
{
// WIC shares the same filter values for mode and dither
static_assert(WIC_FLAGS_DITHER == TEX_FILTER_DITHER, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_DITHER_DIFFUSION == TEX_FILTER_DITHER_DIFFUSION, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_POINT == TEX_FILTER_POINT, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_LINEAR == TEX_FILTER_LINEAR, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_CUBIC == TEX_FILTER_CUBIC, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_FANT == TEX_FILTER_FANT, "WIC_FLAGS_* & TEX_FILTER_* should match");
hr = LoadFromWICFile(pConv->szSrc, dwFilter | WIC_FLAGS_ALL_FRAMES, &info, *image.get()); default:
if (FAILED(hr)) if (_wcsicmp(ext, L".dds") == 0)
{ {
wprintf(L" FAILED (%x)\n", hr); hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image.get());
return 1; if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
if (info.mipLevels > 1
|| info.IsVolumemap()
|| info.IsCubemap())
{
wprintf(L"\nERROR: Can't assemble complex surfaces\n");
return 1;
}
} }
else if (_wcsicmp(ext, L".tga") == 0)
{
hr = LoadFromTGAFile(pConv->szSrc, &info, *image.get());
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
}
else if (_wcsicmp(ext, L".hdr") == 0)
{
hr = LoadFromHDRFile(pConv->szSrc, &info, *image.get());
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
}
else
{
// WIC shares the same filter values for mode and dither
static_assert(WIC_FLAGS_DITHER == TEX_FILTER_DITHER, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_DITHER_DIFFUSION == TEX_FILTER_DITHER_DIFFUSION, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_POINT == TEX_FILTER_POINT, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_LINEAR == TEX_FILTER_LINEAR, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_CUBIC == TEX_FILTER_CUBIC, "WIC_FLAGS_* & TEX_FILTER_* should match");
static_assert(WIC_FLAGS_FILTER_FANT == TEX_FILTER_FANT, "WIC_FLAGS_* & TEX_FILTER_* should match");
hr = LoadFromWICFile(pConv->szSrc, dwFilter | WIC_FLAGS_ALL_FRAMES, &info, *image.get());
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
}
break;
} }
PrintInfo(info); PrintInfo(info);
@ -666,6 +873,42 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
// Convert texture // Convert texture
fflush(stdout); fflush(stdout);
// --- Planar ------------------------------------------------------------------
if (IsPlanar(info.format))
{
auto img = image->GetImage(0, 0, 0);
assert(img);
size_t nimg = image->GetImageCount();
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
hr = ConvertToSinglePlane(img, nimg, info, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [converttosingleplane] (%x)\n", hr);
continue;
}
auto& tinfo = timage->GetMetadata();
info.format = tinfo.format;
assert(info.width == tinfo.width);
assert(info.height == tinfo.height);
assert(info.depth == tinfo.depth);
assert(info.arraySize == tinfo.arraySize);
assert(info.mipLevels == tinfo.mipLevels);
assert(info.miscFlags == tinfo.miscFlags);
assert(info.dimension == tinfo.dimension);
image.swap(timage);
}
// --- Decompress -------------------------------------------------------------- // --- Decompress --------------------------------------------------------------
if (IsCompressed(info.format)) if (IsCompressed(info.format))
{ {
@ -697,12 +940,59 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
assert(info.arraySize == tinfo.arraySize); assert(info.arraySize == tinfo.arraySize);
assert(info.mipLevels == tinfo.mipLevels); assert(info.mipLevels == tinfo.mipLevels);
assert(info.miscFlags == tinfo.miscFlags); assert(info.miscFlags == tinfo.miscFlags);
assert(info.miscFlags2 == tinfo.miscFlags2);
assert(info.dimension == tinfo.dimension); assert(info.dimension == tinfo.dimension);
image.swap(timage); image.swap(timage);
} }
// --- Undo Premultiplied Alpha (if requested) ---------------------------------
if ((dwOptions & (DWORD64(1) << OPT_DEMUL_ALPHA))
&& HasAlpha(info.format)
&& info.format != DXGI_FORMAT_A8_UNORM)
{
if (info.GetAlphaMode() == TEX_ALPHA_MODE_STRAIGHT)
{
printf("\nWARNING: Image is already using straight alpha\n");
}
else if (!info.IsPMAlpha())
{
printf("\nWARNING: Image is not using premultipled alpha\n");
}
else
{
auto img = image->GetImage(0, 0, 0);
assert(img);
size_t nimg = image->GetImageCount();
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
hr = PremultiplyAlpha(img, nimg, info, TEX_PMALPHA_REVERSE | dwSRGB, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [demultiply alpha] (%x)\n", hr);
continue;
}
auto& tinfo = timage->GetMetadata();
info.miscFlags2 = tinfo.miscFlags2;
assert(info.width == tinfo.width);
assert(info.height == tinfo.height);
assert(info.depth == tinfo.depth);
assert(info.arraySize == tinfo.arraySize);
assert(info.mipLevels == tinfo.mipLevels);
assert(info.miscFlags == tinfo.miscFlags);
assert(info.dimension == tinfo.dimension);
image.swap(timage);
}
}
// --- Resize ------------------------------------------------------------------ // --- Resize ------------------------------------------------------------------
if (!width) if (!width)
{ {
@ -738,7 +1028,6 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
assert(info.depth == tinfo.depth); assert(info.depth == tinfo.depth);
assert(info.arraySize == tinfo.arraySize); assert(info.arraySize == tinfo.arraySize);
assert(info.miscFlags == tinfo.miscFlags); assert(info.miscFlags == tinfo.miscFlags);
assert(info.miscFlags2 == tinfo.miscFlags2);
assert(info.format == tinfo.format); assert(info.format == tinfo.format);
assert(info.dimension == tinfo.dimension); assert(info.dimension == tinfo.dimension);
@ -760,7 +1049,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
hr = Convert(image->GetImages(), image->GetImageCount(), image->GetMetadata(), format, hr = Convert(image->GetImages(), image->GetImageCount(), image->GetMetadata(), format,
dwFilter | dwFilterOpts, TEX_THRESHOLD_DEFAULT, *timage.get()); dwFilter | dwFilterOpts | dwSRGB, TEX_THRESHOLD_DEFAULT, *timage.get());
if (FAILED(hr)) if (FAILED(hr))
{ {
wprintf(L" FAILED [convert] (%x)\n", hr); wprintf(L" FAILED [convert] (%x)\n", hr);
@ -778,7 +1067,6 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
assert(info.arraySize == tinfo.arraySize); assert(info.arraySize == tinfo.arraySize);
assert(info.mipLevels == tinfo.mipLevels); assert(info.mipLevels == tinfo.mipLevels);
assert(info.miscFlags == tinfo.miscFlags); assert(info.miscFlags == tinfo.miscFlags);
assert(info.miscFlags2 == tinfo.miscFlags2);
assert(info.dimension == tinfo.dimension); assert(info.dimension == tinfo.dimension);
image.swap(timage); image.swap(timage);
@ -788,32 +1076,198 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
loadedImages.push_back(std::move(image)); loadedImages.push_back(std::move(image));
} }
if (images < 2) switch (dwCommand)
{ {
wprintf(L"\nERROR: Need at least 2 images to assemble\n\n"); case CMD_CUBE:
return 1;
}
switch (dwOptions & ((1 << OPT_CUBE) | (1 << OPT_VOLUME) | (1 << OPT_ARRAY) | (1 << OPT_CUBEARRAY)))
{
case (1 << OPT_CUBE):
if (images != 6) if (images != 6)
{ {
wprintf(L"\nERROR: -cube requires six images to form the faces of the cubemap\n"); wprintf(L"\nERROR: cube requires six images to form the faces of the cubemap\n");
return 1; return 1;
} }
break; break;
case (1 << OPT_CUBEARRAY): case CMD_CUBEARRAY:
if ((images < 6) || (images % 6) != 0) if ((images < 6) || (images % 6) != 0)
{ {
wprintf(L"-cubearray requires a multiple of 6 images to form the faces of the cubemaps\n"); wprintf(L"cubearray requires a multiple of 6 images to form the faces of the cubemaps\n");
return 1;
}
break;
case CMD_H_CROSS:
case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
break;
default:
if (images < 2)
{
wprintf(L"\nERROR: Need at least 2 images to assemble\n\n");
return 1; return 1;
} }
break; break;
} }
// --- Create result --------------------------------------------------------------- // --- Create result ---------------------------------------------------------------
switch (dwCommand)
{
case CMD_H_CROSS:
case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
{
size_t twidth, theight;
switch (dwCommand)
{
case CMD_H_CROSS:
// posy
// negx posz posx negz
// negy
twidth = width * 4;
theight = height * 3;
break;
case CMD_V_CROSS:
// posy
// posz posx negz
// negy
// negx
twidth = width * 3;
theight = height * 4;
break;
case CMD_H_STRIP:
twidth = width * 6;
theight = height;
break;
case CMD_V_STRIP:
twidth = width;
theight = height * 6;
}
ScratchImage result;
hr = result.Initialize2D(format, twidth, theight, 1, 1);
if (FAILED(hr))
{
wprintf(L"FAILED setting up result image (%x)\n", hr);
return 1;
}
memset(result.GetPixels(), 0, result.GetPixelsSize());
auto src = loadedImages.cbegin();
auto dest = result.GetImage(0, 0, 0);
for (size_t index = 0; index < 6; ++index)
{
auto img = (*src)->GetImage(0, index, 0);
if (!img)
{
wprintf(L"FAILED: Unexpected error\n");
return 1;
}
Rect rect(0, 0, width, height);
size_t offsetx = 0;
size_t offsety = 0;
switch (dwCommand)
{
case CMD_H_CROSS:
{
// posy
// negx posz posx negz
// negy
static const size_t s_offsetx[6] = { 2, 0, 1, 1, 1, 3 };
static const size_t s_offsety[6] = { 1, 1, 0, 2, 1, 1 };
offsetx = s_offsetx[index] * width;
offsety = s_offsety[index] * height;
break;
}
case CMD_V_CROSS:
{
// posy
// posz posx negz
// negy
// negx
static const size_t s_offsetx[6] = { 1, 1, 1, 1, 0, 2 };
static const size_t s_offsety[6] = { 1, 3, 0, 2, 1, 1 };
offsetx = s_offsetx[index] * width;
offsety = s_offsety[index] * height;
break;
}
case CMD_H_STRIP:
// posx, negx, posy, negy, posz, negz
offsetx = index * width;
break;
case CMD_V_STRIP:
// posx, negx, posy, negy, posz, negz
offsety = index * height;
break;
}
hr = CopyRectangle(*img, rect, *dest, dwFilter | dwFilterOpts, offsetx, offsety);
if (FAILED(hr))
{
wprintf(L"FAILED building result image (%x)\n", hr);
return 1;
}
}
// Write cross/strip
wprintf(L"\nWriting %ls ", szOutputFile);
PrintInfo(result.GetMetadata());
wprintf(L"\n");
fflush(stdout);
if (~dwOptions & (DWORD64(1) << OPT_OVERWRITE))
{
if (GetFileAttributesW(szOutputFile) != INVALID_FILE_ATTRIBUTES)
{
wprintf(L"\nERROR: Output file already exists, use -y to overwrite\n");
return 1;
}
}
switch (CrossFileType)
{
case CODEC_DDS:
hr = SaveToDDSFile(*dest, DDS_FLAGS_NONE, szOutputFile);
break;
case CODEC_TGA:
hr = SaveToTGAFile(*dest, szOutputFile);
break;
case CODEC_HDR:
hr = SaveToHDRFile(*dest, szOutputFile);
break;
default:
hr = SaveToWICFile(*dest, WIC_FLAGS_NONE, GetWICCodec(static_cast<WICCodecs>(CrossFileType)), szOutputFile);
break;
}
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
break;
}
default:
{ {
std::vector<Image> imageArray; std::vector<Image> imageArray;
imageArray.reserve(images); imageArray.reserve(images);
@ -831,18 +1285,18 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
} }
ScratchImage result; ScratchImage result;
switch (dwOptions & ((1 << OPT_CUBE) | (1 << OPT_VOLUME) | (1 << OPT_ARRAY) | (1 << OPT_CUBEARRAY))) switch (dwCommand)
{ {
case (1 << OPT_VOLUME): case CMD_VOLUME:
hr = result.Initialize3DFromImages(&imageArray[0], imageArray.size()); hr = result.Initialize3DFromImages(&imageArray[0], imageArray.size());
break; break;
case (1 << OPT_ARRAY): case CMD_ARRAY:
hr = result.InitializeArrayFromImages(&imageArray[0], imageArray.size(), (dwOptions & (1 << OPT_USE_DX10)) != 0); hr = result.InitializeArrayFromImages(&imageArray[0], imageArray.size(), (dwOptions & (1 << OPT_USE_DX10)) != 0);
break; break;
case (1 << OPT_CUBE): case CMD_CUBE:
case (1 << OPT_CUBEARRAY): case CMD_CUBEARRAY:
hr = result.InitializeCubeFromImages(&imageArray[0], imageArray.size()); hr = result.InitializeCubeFromImages(&imageArray[0], imageArray.size());
break; break;
} }
@ -859,6 +1313,15 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\n"); wprintf(L"\n");
fflush(stdout); fflush(stdout);
if (~dwOptions & (DWORD64(1) << OPT_OVERWRITE))
{
if (GetFileAttributesW(szOutputFile) != INVALID_FILE_ATTRIBUTES)
{
wprintf(L"\nERROR: Output file already exists, use -y to overwrite\n");
return 1;
}
}
hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(), hr = SaveToDDSFile(result.GetImages(), result.GetImageCount(), result.GetMetadata(),
(dwOptions & (1 << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE, (dwOptions & (1 << OPT_USE_DX10)) ? (DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2) : DDS_FLAGS_NONE,
szOutputFile); szOutputFile);
@ -867,7 +1330,8 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L"\nFAILED (%x)\n", hr); wprintf(L"\nFAILED (%x)\n", hr);
return 1; return 1;
} }
wprintf(L"\n"); break;
}
} }
return 0; return 0;