diff --git a/Texassemble/texassemble.cpp b/Texassemble/texassemble.cpp index 7fc7dc2..309d666 100644 --- a/Texassemble/texassemble.cpp +++ b/Texassemble/texassemble.cpp @@ -96,6 +96,7 @@ namespace OPT_FEATURE_LEVEL, OPT_TONEMAP, OPT_GIF_BGCOLOR, + OPT_SWIZZLE, OPT_MAX }; @@ -156,6 +157,7 @@ namespace { L"fl", OPT_FEATURE_LEVEL }, { L"tonemap", OPT_TONEMAP }, { L"bgcolor", OPT_GIF_BGCOLOR }, + { L"swizzle", OPT_SWIZZLE }, { nullptr, 0 } }; @@ -632,6 +634,8 @@ namespace wprintf(L" -tonemap Apply a tonemap operator based on maximum luminance\n"); wprintf(L"\n (gif only)\n"); wprintf(L" -bgcolor Use background color instead of transparency\n"); + wprintf(L"\n (merge only)\n"); + wprintf(L" -swizzle Select channels for merge (defaults to rgbB)\n"); wprintf(L"\n : "); PrintList(13, g_pFormats); @@ -668,6 +672,78 @@ namespace return SaveToWICFile(img, WIC_FLAGS_NONE, GetWICCodec(static_cast(fileType)), szOutputFile); } } + + + bool ParseSwizzleMask(_In_reads_(4) const wchar_t* mask, _Out_writes_(4) uint32_t* permuteElements) + { + if (!mask || !permuteElements) + return false; + + if (!mask[0]) + return false; + + for (size_t j = 0; j < 4; ++j) + { + if (!mask[j]) + break; + + switch (mask[j]) + { + case L'r': + case L'x': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 0; + break; + + case L'R': + case L'X': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 4; + break; + + case L'g': + case L'y': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 1; + break; + + case L'G': + case L'Y': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 5; + break; + + case L'b': + case L'z': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 2; + break; + + case L'B': + case L'Z': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 6; + break; + + case L'a': + case L'w': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 3; + break; + + case L'A': + case L'W': + for (size_t k = j; k < 4; ++k) + permuteElements[k] = 7; + break; + + default: + return false; + } + } + + return true; + } } //-------------------------------------------------------------------------------------- @@ -693,6 +769,9 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) DWORD maxArray = 2048; DWORD maxVolume = 2048; + // DXTex's Open Alpha onto Surface always loaded alpha from the blue channel + uint32_t permuteElements[4] = { 0, 1, 2, 6 }; + wchar_t szOutputFile[MAX_PATH] = {}; // Initialize COM (needed for WIC) @@ -768,6 +847,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) case OPT_FILTER: case OPT_OUTPUTFILE: case OPT_FEATURE_LEVEL: + case OPT_SWIZZLE: if (!*pValue) { if ((iArg + 1 >= argc)) @@ -958,6 +1038,25 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) } break; + case OPT_SWIZZLE: + if (dwCommand != CMD_MERGE) + { + wprintf(L"-swizzle only applies to merge command\n"); + return 1; + } + if (!*pValue || wcslen(pValue) > 4) + { + wprintf(L"Invalid value specified with -swizzle (%ls)\n\n", pValue); + PrintUsage(); + return 1; + } + else if (!ParseSwizzleMask(pValue, permuteElements)) + { + wprintf(L"-swizzle requires a 1 to 4 character mask composed of these letters: r, g, b, a, x, y, w, z.\n Lowercase letters are from the first image, upper-case letters are from the second image.\n"); + return 1; + } + break; + default: break; } @@ -1688,54 +1787,30 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) case CMD_MERGE: { - // Capture alpha from source image (the second input filename) - ScratchImage alphaImage; - hr = alphaImage.Initialize2D(DXGI_FORMAT_R32_FLOAT, width, height, 1, 1); + // Capture data from our second source image + ScratchImage tempImage; + hr = Convert(*loadedImages[1]->GetImage(0, 0, 0), DXGI_FORMAT_R32G32B32A32_FLOAT, + dwFilter | dwFilterOpts | dwSRGB, TEX_THRESHOLD_DEFAULT, tempImage); if (FAILED(hr)) { - wprintf(L"FAILED setting up alpha image (%x)\n", static_cast(hr)); + wprintf(L" FAILED [convert second input] (%x)\n", static_cast(hr)); return 1; } - const Image& img = *alphaImage.GetImage(0, 0, 0); + const Image& img = *tempImage.GetImage(0, 0, 0); - hr = EvaluateImage(*loadedImages[1]->GetImage(0, 0, 0), - [&](const XMVECTOR* pixels, size_t w, size_t y) - { - auto alphaPtr = reinterpret_cast(img.pixels + img.rowPitch * y); - - for (size_t j = 0; j < w; ++j) - { - XMVECTOR value = pixels[j]; - - // DXTex's Open Alpha onto Surface always loaded alpha from the blue channel - - *alphaPtr++ = XMVectorGetZ(value); - } - }); - if (FAILED(hr)) - { - wprintf(L" FAILED [reading alpha image] (%x)\n", static_cast(hr)); - return 1; - } - - // Merge with rgb from our source iamge (the first input filename) + // Merge with our first source image const Image& rgb = *loadedImages[0]->GetImage(0, 0, 0); ScratchImage result; hr = TransformImage(rgb, [&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y) { - auto alphaPtr = reinterpret_cast(img.pixels + img.rowPitch * y); + const XMVECTOR *inPixels2 = reinterpret_cast(img.pixels + img.rowPitch * y); for (size_t j = 0; j < w; ++j) { - XMVECTOR value = inPixels[j]; - - XMVECTOR nvalue = XMVectorReplicate(*alphaPtr++); - - value = XMVectorSelect(nvalue, value, g_XMSelect1110); - - outPixels[j] = value; + outPixels[j] = XMVectorPermute(inPixels[j], inPixels2[j], + permuteElements[0], permuteElements[1], permuteElements[2], permuteElements[3]); } }, result); if (FAILED(hr))