From df72538e93df58f56a03027f73d0fe39118da7ca Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 24 Sep 2016 01:06:54 -0700 Subject: [PATCH] texassemble: command syntax with strip/cross, -srgb, -y, -wrap, -mirror, -alpha switches --- Texassemble/texassemble.cpp | 664 ++++++++++++++++++++++++++++++------ 1 file changed, 564 insertions(+), 100 deletions(-) diff --git a/Texassemble/texassemble.cpp b/Texassemble/texassemble.cpp index 98c1e01..2da32b3 100644 --- a/Texassemble/texassemble.cpp +++ b/Texassemble/texassemble.cpp @@ -32,21 +32,37 @@ 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 { OPT_RECURSIVE = 1, - OPT_CUBE, - OPT_VOLUME, - OPT_ARRAY, - OPT_CUBEARRAY, OPT_WIDTH, OPT_HEIGHT, OPT_FORMAT, OPT_FILTER, + OPT_SRGBI, + OPT_SRGBO, + OPT_SRGB, OPT_OUTPUTFILE, + OPT_OVERWRITE, OPT_USE_DX10, OPT_NOLOGO, OPT_SEPALPHA, + OPT_DEMUL_ALPHA, + OPT_TA_WRAP, + OPT_TA_MIRROR, 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[] = { { 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"h", OPT_HEIGHT }, { L"f", OPT_FORMAT }, { L"if", OPT_FILTER }, + { L"srgbi", OPT_SRGBI }, + { L"srgbo", OPT_SRGBO }, + { L"srgb", OPT_SRGB }, { L"o", OPT_OUTPUTFILE }, + { L"y", OPT_OVERWRITE }, { L"dx10", OPT_USE_DX10 }, { L"nologo", OPT_NOLOGO }, { L"sepalpha", OPT_SEPALPHA }, + { L"alpha", OPT_DEMUL_ALPHA }, + { L"wrap", OPT_TA_WRAP }, + { L"mirror", OPT_TA_MIRROR }, { nullptr, 0 } }; @@ -149,6 +181,13 @@ SValue g_pFormats[] = DEFFMT(B8G8R8X8_UNORM_SRGB), // 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), { nullptr, DXGI_FORMAT_UNKNOWN } @@ -177,6 +216,27 @@ SValue g_pFilters[] = { 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; } + 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")"); } @@ -385,28 +458,31 @@ namespace { PrintLogo(); - wprintf(L"Usage: texassemble [-cube | - volume | -array | -cubearray] \n"); - wprintf(L"\n"); + wprintf(L"Usage: texassemble \n\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" -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 width\n"); wprintf(L" -h height\n"); wprintf(L" -f format\n"); wprintf(L" -if image filtering\n"); + wprintf(L" -srgb{i|o} sRGB {input, output}\n"); wprintf(L" -o 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" -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" -nologo suppress copyright message\n"); - wprintf(L"\n"); - wprintf(L" : "); + wprintf(L"\n : "); PrintList(13, g_pFormats); - wprintf(L"\n"); - wprintf(L" : "); + wprintf(L"\n : "); 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; DWORD dwFilter = TEX_FILTER_DEFAULT; + DWORD dwSRGB = 0; DWORD dwFilterOpts = 0; + DWORD CrossFileType = WIC_CODEC_BMP; 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; std::list 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]; @@ -522,12 +624,69 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) } 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: dwFilterOpts |= TEX_FILTER_SEPARATE_ALPHA; break; case OPT_OUTPUTFILE: + { 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; } } @@ -556,22 +715,23 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) 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)) 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 size_t images = 0; @@ -588,13 +748,25 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) wprintf(L"\n"); else if (!*szOutputFile) { - if (_wcsicmp(ext, L".dds") == 0) + switch (dwCommand) { - wprintf(L"ERROR: Need to specify output file via -o\n"); - return 1; - } + case CMD_H_CROSS: + 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); @@ -608,57 +780,92 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) return 1; } - if (_wcsicmp(ext, L".dds") == 0) + switch (dwCommand) { - hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image.get()); - if (FAILED(hr)) + case CMD_H_CROSS: + case CMD_V_CROSS: + case CMD_H_STRIP: + case CMD_V_STRIP: + if (_wcsicmp(ext, L".dds") == 0) { - wprintf(L" FAILED (%x)\n", hr); - return 1; - } + hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image.get()); + if (FAILED(hr)) + { + wprintf(L" FAILED (%x)\n", hr); + return 1; + } - if (info.depth > 1 - || info.mipLevels > 1 - || info.IsCubemap()) + if (!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; } - } - 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"); + break; - hr = LoadFromWICFile(pConv->szSrc, dwFilter | WIC_FLAGS_ALL_FRAMES, &info, *image.get()); - if (FAILED(hr)) + default: + if (_wcsicmp(ext, L".dds") == 0) { - wprintf(L" FAILED (%x)\n", hr); - return 1; + hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image.get()); + 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); @@ -666,6 +873,42 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) // Convert texture fflush(stdout); + // --- Planar ------------------------------------------------------------------ + if (IsPlanar(info.format)) + { + auto img = image->GetImage(0, 0, 0); + assert(img); + size_t nimg = image->GetImageCount(); + + std::unique_ptr 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 -------------------------------------------------------------- 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.mipLevels == tinfo.mipLevels); assert(info.miscFlags == tinfo.miscFlags); - assert(info.miscFlags2 == tinfo.miscFlags2); assert(info.dimension == tinfo.dimension); 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 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 ------------------------------------------------------------------ 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.arraySize == tinfo.arraySize); assert(info.miscFlags == tinfo.miscFlags); - assert(info.miscFlags2 == tinfo.miscFlags2); assert(info.format == tinfo.format); 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, - dwFilter | dwFilterOpts, TEX_THRESHOLD_DEFAULT, *timage.get()); + dwFilter | dwFilterOpts | dwSRGB, TEX_THRESHOLD_DEFAULT, *timage.get()); if (FAILED(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.mipLevels == tinfo.mipLevels); assert(info.miscFlags == tinfo.miscFlags); - assert(info.miscFlags2 == tinfo.miscFlags2); assert(info.dimension == tinfo.dimension); 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)); } - if (images < 2) + switch (dwCommand) { - wprintf(L"\nERROR: Need at least 2 images to assemble\n\n"); - return 1; - } - - switch (dwOptions & ((1 << OPT_CUBE) | (1 << OPT_VOLUME) | (1 << OPT_ARRAY) | (1 << OPT_CUBEARRAY))) - { - case (1 << OPT_CUBE): + case CMD_CUBE: 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; } break; - case (1 << OPT_CUBEARRAY): + case CMD_CUBEARRAY: 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; } break; } // --- 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(CrossFileType)), szOutputFile); + break; + } + + if (FAILED(hr)) + { + wprintf(L" FAILED (%x)\n", hr); + return 1; + } + break; + } + + default: { std::vector imageArray; imageArray.reserve(images); @@ -831,18 +1285,18 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) } 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()); break; - case (1 << OPT_ARRAY): + case CMD_ARRAY: hr = result.InitializeArrayFromImages(&imageArray[0], imageArray.size(), (dwOptions & (1 << OPT_USE_DX10)) != 0); break; - case (1 << OPT_CUBE): - case (1 << OPT_CUBEARRAY): + case CMD_CUBE: + case CMD_CUBEARRAY: hr = result.InitializeCubeFromImages(&imageArray[0], imageArray.size()); break; } @@ -859,6 +1313,15 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) 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; + } + } + 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, szOutputFile); @@ -867,7 +1330,8 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) wprintf(L"\nFAILED (%x)\n", hr); return 1; } - wprintf(L"\n"); + break; + } } return 0;