Merge branch 'master' into cs50

This commit is contained in:
Chuck Walbourn 2019-01-29 00:04:43 -08:00
commit e6f78c53af
13 changed files with 638 additions and 30 deletions

View File

@ -7,10 +7,10 @@
<authors>Microsoft</authors>
<owners>microsoft,directxtk</owners>
<summary>DirectXTex texture processing library</summary>
<description>This version is for Windows desktop applications using Visual Studio 2015 Update 3 or Visual Studio 2017.
<description>This version is for Windows desktop applications using Visual Studio 2015 Update 3 or Visual Studio 2017 and supports Windows 7 / DirectX 11.
DirectXTex, a shared source library for reading and writing .DDS files, and performing various texture content processing operations including resizing, format conversion, mip-map generation, block compression for Direct3D runtime texture resources, and height-map to normal-map conversion. This library makes use of the Windows Image Component (WIC) APIs. It also includes simple .TGA and .HDR readers and writers since these image file format are commonly used for texture content processing pipelines, but are not currently supported by a built-in WIC codec.</description>
<releaseNotes>Matches the October 25, 2018 release on GitHub.</releaseNotes>
<releaseNotes>Matches the November 16, 2018 release on GitHub.</releaseNotes>
<projectUrl>http://go.microsoft.com/fwlink/?LinkId=248926</projectUrl>
<iconUrl>https://github.com/Microsoft/DirectXTex/wiki/X_jpg.jpg</iconUrl>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="2.8.6">
<id>directxtex_desktop_win10</id>
<version>0.0.0-SpecifyVersionOnCommandline</version>
<title>DirectXTex Library (VS 2015/VS 2017 Win32 for Windows 10)</title>
<authors>Microsoft</authors>
<owners>microsoft,directxtk</owners>
<summary>DirectXTex texture processing library</summary>
<description>This version is for Windows desktop applications using Visual Studio 2015 Update 3 or Visual Studio 2017 and supports Windows 10 including both DirectX 11 and DirectX 12.
DirectXTex, a shared source library for reading and writing .DDS files, and performing various texture content processing operations including resizing, format conversion, mip-map generation, block compression for Direct3D runtime texture resources, and height-map to normal-map conversion. This library makes use of the Windows Image Component (WIC) APIs. It also includes simple .TGA and .HDR readers and writers since these image file format are commonly used for texture content processing pipelines, but are not currently supported by a built-in WIC codec.</description>
<releaseNotes>Matches the November 16, 2018 release on GitHub.</releaseNotes>
<projectUrl>http://go.microsoft.com/fwlink/?LinkId=248926</projectUrl>
<iconUrl>https://github.com/Microsoft/DirectXTex/wiki/X_jpg.jpg</iconUrl>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<tags>DirectX DirectXTex native nativepackage</tags>
</metadata>
<files>
<file target="docs" src="Readme.*" />
<file target="include" src="DirectXTex\DirectXTex.h" />
<file target="include" src="DirectXTex\DirectXTex.inl" />
<file target="lib\Win32\Debug" src="DirectXTex\Bin\Desktop_2015_Win10\Win32\Debug\*.lib" />
<file target="lib\Win32\Debug" src="DirectXTex\Bin\Desktop_2015_Win10\Win32\Debug\*.pdb" />
<file target="lib\Win32\Release" src="DirectXTex\Bin\Desktop_2015_Win10\Win32\Release\*.lib" />
<file target="lib\Win32\Release" src="DirectXTex\Bin\Desktop_2015_Win10\Win32\Release\*.pdb" />
<file target="lib\x64\Debug" src="DirectXTex\Bin\Desktop_2015_Win10\x64\Debug\*.lib" />
<file target="lib\x64\Debug" src="DirectXTex\Bin\Desktop_2015_Win10\x64\Debug\*.pdb" />
<file target="lib\x64\Release" src="DirectXTex\Bin\Desktop_2015_Win10\x64\Release\*.lib" />
<file target="lib\x64\Release" src="DirectXTex\Bin\Desktop_2015_Win10\x64\Release\*.pdb" />
<file src=".nuget/directxtex_desktop_win10.targets" target="build\native" />
</files>
</package>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<directxtex-LibPath>$(MSBuildThisFileDirectory)..\..\lib\$(Platform)\$(Configuration)</directxtex-LibPath>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalLibraryDirectories>$(directxtex-LibPath);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>DirectXTex.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>HAS_DIRECTXTEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@ -10,7 +10,7 @@
<description>This version is for Universal Windows Platform apps on Windows 10 using Visual Studio 2015 Update 3 or Visual Studio 2017.
DirectXTex, a shared source library for reading and writing .DDS files, and performing various texture content processing operations including resizing, format conversion, mip-map generation, block compression for Direct3D runtime texture resources, and height-map to normal-map conversion. This library makes use of the Windows Image Component (WIC) APIs. It also includes simple .TGA and .HDR readers and writers since these image file format are commonly used for texture content processing pipelines, but are not currently supported by a built-in WIC codec.</description>
<releaseNotes>Matches the October 25, 2018 release on GitHub.</releaseNotes>
<releaseNotes>Matches the November 16, 2018 release on GitHub.</releaseNotes>
<projectUrl>http://go.microsoft.com/fwlink/?LinkId=248926</projectUrl>
<iconUrl>https://github.com/Microsoft/DirectXTex/wiki/X_jpg.jpg</iconUrl>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
@ -32,6 +32,12 @@ DirectXTex, a shared source library for reading and writing .DDS files, and perf
<file target="lib\ARM\Release" src="DirectXTex\Bin\Windows10\ARM\Release\*.lib" />
<file target="lib\ARM\Release" src="DirectXTex\Bin\Windows10\ARM\Release\*.pdb" />
<file target="lib\ARM64\Debug" src="DirectXTex\Bin\Windows10\ARM64\Debug\*.lib" />
<file target="lib\ARM64\Debug" src="DirectXTex\Bin\Windows10\ARM64\Debug\*.pdb" />
<file target="lib\ARM64\Release" src="DirectXTex\Bin\Windows10\ARM64\Release\*.lib" />
<file target="lib\ARM64\Release" src="DirectXTex\Bin\Windows10\ARM64\Release\*.pdb" />
<file target="lib\Win32\Debug" src="DirectXTex\Bin\Windows10\Win32\Debug\*.lib" />
<file target="lib\Win32\Debug" src="DirectXTex\Bin\Windows10\Win32\Debug\*.pdb" />

View File

@ -2,5 +2,6 @@
<SignConfigXML>
<job dest="__OUTPATHROOT__" certSubject="NuGet" jobname="NugetSigningTest">
<file src="__INPATHROOT__\directxtex_desktop_2015*.nupkg" signType="CP-401405" dest="__OUTPATHROOT__\directxtex_desktop_2015*.nupkg" />
<file src="__INPATHROOT__\directxtex_desktop_win10*.nupkg" signType="CP-401405" dest="__OUTPATHROOT__\directxtex_desktop_win10*.nupkg" />
</job>
</SignConfigXML>

View File

@ -194,6 +194,12 @@ namespace DirectX
WIC_FLAGS_IGNORE_SRGB = 0x20,
// Ignores sRGB metadata if present in the file
WIC_FLAGS_FORCE_SRGB = 0x40,
// Writes sRGB metadata into the file reguardless of format
WIC_FLAGS_FORCE_LINEAR = 0x80,
// Writes linear gamma metadata into the file reguardless of format
WIC_FLAGS_DITHER = 0x10000,
// Use ordered 4x4 dithering for any required conversions
@ -528,6 +534,11 @@ namespace DirectX
// levels of '0' indicates a full mipchain, otherwise is generates that number of total levels (including the source base image)
// Defaults to Fant filtering which is equivalent to a box filter
HRESULT __cdecl ScaleMipMapsAlphaForCoverage(
_In_reads_(nimages) const Image* srcImages, _In_ size_t nimages, _In_ const TexMetadata& metadata, _In_ size_t item,
_In_ float alphaReference, _Inout_ ScratchImage& mipChain);
enum TEX_PMALPHA_FLAGS
{
TEX_PMALPHA_DEFAULT = 0,

View File

@ -116,6 +116,233 @@ namespace
return hr;
}
#if DIRECTX_MATH_VERSION >= 310
#define VectorSum XMVectorSum
#else
inline XMVECTOR XM_CALLCONV VectorSum
(
FXMVECTOR V
)
{
XMVECTOR vTemp = XMVectorSwizzle<2, 3, 0, 1>(V);
XMVECTOR vTemp2 = XMVectorAdd(V, vTemp);
vTemp = XMVectorSwizzle<1, 0, 3, 2>(vTemp2);
return XMVectorAdd(vTemp, vTemp2);
}
#endif
HRESULT ScaleAlpha(
const Image& srcImage,
float alphaScale,
const Image& destImage)
{
assert(srcImage.width == destImage.width);
assert(srcImage.height == destImage.height);
ScopedAlignedArrayXMVECTOR scanline(reinterpret_cast<XMVECTOR*>(_aligned_malloc((sizeof(XMVECTOR)*srcImage.width), 16)));
if (!scanline)
{
return E_OUTOFMEMORY;
}
const uint8_t* pSrc = srcImage.pixels;
uint8_t* pDest = destImage.pixels;
if (!pSrc || !pDest)
{
return E_POINTER;
}
const XMVECTOR vscale = XMVectorReplicate(alphaScale);
for (size_t h = 0; h < srcImage.height; ++h)
{
if (!_LoadScanline(scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format))
{
return E_FAIL;
}
XMVECTOR* ptr = scanline.get();
for (size_t w = 0; w < srcImage.width; ++w)
{
XMVECTOR v = *ptr;
XMVECTOR alpha = XMVectorMultiply(XMVectorSplatW(v), vscale);
*(ptr++) = XMVectorSelect(alpha, v, g_XMSelect1110);
}
if (!_StoreScanline(pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width))
{
return E_FAIL;
}
pSrc += srcImage.rowPitch;
pDest += destImage.rowPitch;
}
return S_OK;
}
void GenerateAlphaCoverageConvolutionVectors(
_In_ size_t N,
_Out_writes_(N*N) XMVECTOR* vectors)
{
for (size_t sy = 0; sy < N; ++sy)
{
const float fy = (sy + 0.5f) / N;
const float ify = 1.0f - fy;
for (size_t sx = 0; sx < N; ++sx)
{
const float fx = (sx + 0.5f) / N;
const float ifx = 1.0f - fx;
// [0]=(x+0, y+0), [1]=(x+0, y+1), [2]=(x+1, y+0), [3]=(x+1, y+1)
vectors[sy * N + sx] = XMVectorSet(ifx * ify, ifx * fy, fx * ify, fx * fy);
}
}
}
HRESULT CalculateAlphaCoverage(
const Image& srcImage,
float alphaReference,
float alphaScale,
float& coverage)
{
coverage = 0.0f;
ScopedAlignedArrayXMVECTOR row0(reinterpret_cast<XMVECTOR*>(_aligned_malloc((sizeof(XMVECTOR)*srcImage.width), 16)));
if (!row0)
{
return E_OUTOFMEMORY;
}
ScopedAlignedArrayXMVECTOR row1(reinterpret_cast<XMVECTOR*>(_aligned_malloc((sizeof(XMVECTOR)*srcImage.width), 16)));
if (!row1)
{
return E_OUTOFMEMORY;
}
const DWORD flags = 0;
const XMVECTOR scale = XMVectorReplicate(alphaScale);
const uint8_t *pSrcRow0 = srcImage.pixels;
if (!pSrcRow0)
{
return E_POINTER;
}
const size_t N = 8;
XMVECTOR convolution[N * N];
GenerateAlphaCoverageConvolutionVectors(N, convolution);
size_t coverageCount = 0;
for (size_t y = 0; y < srcImage.height - 1; ++y)
{
if (!_LoadScanlineLinear(row0.get(), srcImage.width, pSrcRow0, srcImage.rowPitch, srcImage.format, flags))
{
return E_FAIL;
}
const uint8_t *pSrcRow1 = pSrcRow0 + srcImage.rowPitch;
if (!_LoadScanlineLinear(row1.get(), srcImage.width, pSrcRow1, srcImage.rowPitch, srcImage.format, flags))
{
return E_FAIL;
}
const XMVECTOR* pRow0 = row0.get();
const XMVECTOR* pRow1 = row1.get();
for (size_t x = 0; x < srcImage.width - 1; ++x)
{
// [0]=(x+0, y+0), [1]=(x+0, y+1), [2]=(x+1, y+0), [3]=(x+1, y+1)
XMVECTOR v1 = XMVectorSaturate(XMVectorMultiply(XMVectorSplatW(*pRow0), scale));
XMVECTOR v2 = XMVectorSaturate(XMVectorMultiply(XMVectorSplatW(*pRow1), scale));
XMVECTOR v3 = XMVectorSaturate(XMVectorMultiply(XMVectorSplatW(*(pRow0++)), scale));
XMVECTOR v4 = XMVectorSaturate(XMVectorMultiply(XMVectorSplatW(*(pRow1++)), scale));
v1 = XMVectorMergeXY(v1, v2); // [v1.x v2.x --- ---]
v3 = XMVectorMergeXY(v3, v4); // [v3.x v4.x --- ---]
XMVECTOR v = XMVectorPermute<0, 1, 4, 5>(v1, v3); // [v1.x v2.x v3.x v4.x]
for (size_t sy = 0; sy < N; ++sy)
{
const size_t ry = sy * N;
for (size_t sx = 0; sx < N; ++sx)
{
v = VectorSum(XMVectorMultiply(v, convolution[ry + sx]));
if (XMVectorGetX(v) > alphaReference)
{
++coverageCount;
}
}
}
}
pSrcRow0 = pSrcRow1;
}
float cscale = static_cast<float>((srcImage.width - 1) * (srcImage.height - 1) * N * N);
if (cscale > 0.f)
{
coverage = static_cast<float>(coverageCount) / cscale;
}
return S_OK;
}
HRESULT EstimateAlphaScaleForCoverage(
const Image& srcImage,
float alphaReference,
float targetCoverage,
float& alphaScale)
{
float minAlphaScale = 0.0f;
float maxAlphaScale = 4.0f;
float bestAlphaScale = 1.0f;
float bestError = FLT_MAX;
// Determine desired scale using a binary search. Hardcoded to 10 steps max.
alphaScale = 1.0f;
const size_t N = 10;
for (size_t i = 0; i < N; ++i)
{
float currentCoverage = 0.0f;
HRESULT hr = CalculateAlphaCoverage(srcImage, alphaReference, alphaScale, currentCoverage);
if (FAILED(hr))
{
return hr;
}
const float error = fabsf(currentCoverage - targetCoverage);
if (error < bestError)
{
bestError = error;
bestAlphaScale = alphaScale;
}
if (currentCoverage < targetCoverage)
{
minAlphaScale = alphaScale;
}
else if (currentCoverage > targetCoverage)
{
maxAlphaScale = alphaScale;
}
else
{
break;
}
alphaScale = (minAlphaScale + maxAlphaScale) * 0.5f;
}
return S_OK;
}
}
@ -3179,3 +3406,75 @@ HRESULT DirectX::GenerateMipMaps3D(
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
}
_Use_decl_annotations_
HRESULT DirectX::ScaleMipMapsAlphaForCoverage(
const Image* srcImages,
size_t nimages,
const TexMetadata& metadata,
size_t item,
float alphaReference,
ScratchImage& mipChain)
{
if (!srcImages || !nimages || !IsValid(metadata.format) || nimages > metadata.mipLevels || !mipChain.GetImages())
return E_INVALIDARG;
if (metadata.IsVolumemap()
|| IsCompressed(metadata.format) || IsTypeless(metadata.format) || IsPlanar(metadata.format) || IsPalettized(metadata.format))
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
if (srcImages[0].format != metadata.format || srcImages[0].width != metadata.width || srcImages[0].height != metadata.height)
{
// Base image must be the same format, width, and height
return E_FAIL;
}
float targetCoverage = 0.0f;
HRESULT hr = CalculateAlphaCoverage(srcImages[0], alphaReference, 1.0f, targetCoverage);
if (FAILED(hr))
return hr;
// Copy base image
{
const Image& src = srcImages[0];
const Image *dest = mipChain.GetImage(0, item, 0);
if (!dest)
return E_POINTER;
uint8_t* pDest = dest->pixels;
if (!pDest)
return E_POINTER;
const uint8_t *pSrc = src.pixels;
size_t rowPitch = src.rowPitch;
for (size_t h = 0; h < metadata.height; ++h)
{
size_t msize = std::min<size_t>(dest->rowPitch, rowPitch);
memcpy_s(pDest, dest->rowPitch, pSrc, msize);
pSrc += rowPitch;
pDest += dest->rowPitch;
}
}
for (size_t level = 1; level < metadata.mipLevels; ++level)
{
if (level >= nimages)
return E_FAIL;
float alphaScale = 0.0f;
hr = EstimateAlphaScaleForCoverage(srcImages[level], alphaReference, targetCoverage, alphaScale);
if (FAILED(hr))
return hr;
const Image* mipImage = mipChain.GetImage(level, item, 0);
if (!mipImage)
return E_POINTER;
hr = ScaleAlpha(srcImages[level], alphaScale, *mipImage);
if (FAILED(hr))
return hr;
}
return S_OK;
}

View File

@ -570,6 +570,7 @@ namespace
// Encodes image metadata
//-------------------------------------------------------------------------------------
HRESULT EncodeMetadata(
DWORD flags,
_In_ IWICBitmapFrameEncode* frame,
const GUID& containerFormat,
DXGI_FORMAT format)
@ -584,7 +585,7 @@ namespace
PROPVARIANT value;
PropVariantInit(&value);
bool sRGB = IsSRGB(format);
bool sRGB = ((flags & WIC_FLAGS_FORCE_LINEAR) == 0) && ((flags & WIC_FLAGS_FORCE_SRGB) != 0 || IsSRGB(format));
value.vt = VT_LPSTR;
value.pszVal = const_cast<char*>("DirectXTex");
@ -715,7 +716,7 @@ namespace
return E_FAIL;
}
hr = EncodeMetadata(frame, containerFormat, image.format);
hr = EncodeMetadata(flags, frame, containerFormat, image.format);
if (FAILED(hr))
return hr;

View File

@ -2666,7 +2666,7 @@ inline HRESULT D3DX12ParsePipelineStream(const D3D12_PIPELINE_STATE_STREAM_DESC&
}
#endif // NTDDI_WIN10_RS2
// Requires the Windows 10 April 2018 Update SDK (17763)
// Requires the Windows 10 October 2018 Update SDK (17763)
#if defined(NTDDI_WIN10_RS5) && (NTDDI_VERSION >= NTDDI_WIN10_RS5)
//------------------------------------------------------------------------------------------------
inline bool operator==( const D3D12_CLEAR_VALUE &a, const D3D12_CLEAR_VALUE &b)

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2018 Microsoft Corp
Copyright (c) 2011-2019 Microsoft Corp
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software

View File

@ -3,7 +3,7 @@ DIRECTX TEXTURE LIBRARY (DirectXTex)
Copyright (c) Microsoft Corporation. All rights reserved.
October 25, 2018
November 16, 2018
This package contains DirectXTex, a shared source library for reading and writing DDS
files, and performing various texture content processing operations including
@ -15,8 +15,8 @@ processing pipelines, but are not currently supported by a built-in WIC codec.
This code is designed to build with Visual Studio 2015 Update 3 or Visual Studio 2017.
It is recommended that you make use of VS 2015 Update 3, Windows Tools 1.4.1, and the
Windows 10 Anniversary Update SDK (14393) or VS 2017 (15.8 update) with the
Windows 10 April 2018 Update SDK (17134).
Windows 10 Anniversary Update SDK (14393) -or- VS 2017 (15.9 update) with the
Windows 10 October 2018 Update SDK (17763).
DirectXTex\
This contains the DirectXTex library. This includes a full-featured DDS reader and writer
@ -125,17 +125,23 @@ RELEASE NOTES
with the system headers. You can work around these by disabling this switch in the project files which is found
in the <ConformanceMode> elements.
* The VS 2017 projects require the 15.5 update or later. For UWP and Win32 classic desktop projects with the 15.5
or 15.6 updates, you need to install the standalone Windows 10 SDK (17134) which is otherwise included in
the 15.7/15.8 update. Older VS 2017 updates will fail to load the projects due to use of the <ConformanceMode> element.
* The VS 2017 projects require the 15.5 update or later. For UWP and Win32 classic desktop projects with the 15.5 -
15.7 updates, you need to install the standalone Windows 10 SDK (17763) which is otherwise included in the 15.8.6 or
later update. Older VS 2017 updates will fail to load the projects due to use of the <ConformanceMode> element.
If using the 15.5 or 15.6 updates, you will see "warning D9002: ignoring unknown option '/Zc:__cplusplus'" because
this switch isn't supported until 15.7. It is safe to ignore this warning, or you can edit the project files
<AdditionalOptions> elements.
* The UWP projects include configurations for the ARM64 platform. These require VS 2017 (15.9 update) to build.
------------------------------------
RELEASE HISTORY
November 16, 2018
VS 2017 updated for Windows 10 October 2018 Update SDK (17763)
ARM64 platform configurations added to UWP projects
October 25, 2018
Use UTF-8 instead of ANSI for narrow strings
Updated D3DX12 internal copy to latest version

View File

@ -62,6 +62,7 @@ enum COMMANDS
CMD_V_STRIP,
CMD_MERGE,
CMD_GIF,
CMD_ARRAY_STRIP,
CMD_MAX
};
@ -109,17 +110,18 @@ struct SValue
const 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 },
{ L"merge", CMD_MERGE },
{ L"gif", CMD_GIF },
{ nullptr, 0 }
{ 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 },
{ L"merge", CMD_MERGE },
{ L"gif", CMD_GIF },
{ L"array-strip", CMD_ARRAY_STRIP },
{ nullptr, 0 }
};
const SValue g_pOptions [] =
@ -510,6 +512,7 @@ namespace
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");
wprintf(L" array-strip creates a strip image from a 1D/2D array\n");
wprintf(L" merge create texture from rgb image and alpha image\n");
wprintf(L" gif create array from animated gif\n\n");
wprintf(L" -r wildcard filename search is recursive\n");
@ -958,10 +961,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case CMD_V_STRIP:
case CMD_MERGE:
case CMD_GIF:
case CMD_ARRAY_STRIP:
break;
default:
wprintf(L"Must use one of: cube, volume, array, cubearray,\n h-cross, v-cross, h-strip, v-strip\n merge, gif\n\n");
wprintf(L"Must use one of: cube, volume, array, cubearray,\n h-cross, v-cross, h-strip, v-strip, array-strip\n merge, gif\n\n");
return 1;
}
@ -1090,6 +1094,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case CMD_H_STRIP:
case CMD_V_STRIP:
case CMD_MERGE:
case CMD_ARRAY_STRIP:
break;
default:
@ -1208,6 +1213,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case CMD_H_STRIP:
case CMD_V_STRIP:
case CMD_GIF:
case CMD_ARRAY_STRIP:
if (conversion.size() > 1)
{
wprintf(L"ERROR: cross/strip/gif output only accepts 1 input file\n");
@ -1269,6 +1275,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case CMD_V_CROSS:
case CMD_H_STRIP:
case CMD_V_STRIP:
case CMD_ARRAY_STRIP:
_wmakepath_s(szOutputFile, nullptr, nullptr, fname, L".bmp");
break;
@ -1327,6 +1334,29 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
}
break;
case CMD_ARRAY_STRIP:
if (_wcsicmp(ext, L".dds") == 0)
{
hr = LoadFromDDSFile(pConv->szSrc, DDS_FLAGS_NONE, &info, *image);
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
if (info.dimension == TEX_DIMENSION_TEXTURE3D || info.arraySize < 2 || info.IsCubemap())
{
wprintf(L"\nERROR: Input must be a 1D/2D array\n");
return 1;
}
}
else
{
wprintf(L"\nERROR: Input must be a dds of a 1D/2D array\n");
return 1;
}
break;
default:
if (_wcsicmp(ext, L".dds") == 0)
{
@ -1938,6 +1968,71 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
break;
}
case CMD_ARRAY_STRIP:
{
size_t twidth = width;
size_t theight = height * images;
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 < images; ++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;
offsety = index * height;
hr = CopyRectangle(*img, rect, *dest, dwFilter | dwFilterOpts, offsetx, offsety);
if (FAILED(hr))
{
wprintf(L"FAILED building result image (%x)\n", hr);
return 1;
}
}
// Write array strip
wprintf(L"\nWriting %ls ", szOutputFile);
PrintInfo(result.GetMetadata());
wprintf(L"\n");
fflush(stdout);
if (~dwOptions & (1 << OPT_OVERWRITE))
{
if (GetFileAttributesW(szOutputFile) != INVALID_FILE_ATTRIBUTES)
{
wprintf(L"\nERROR: Output file already exists, use -y to overwrite\n");
return 1;
}
}
hr = SaveImageFile(*dest, fileType, szOutputFile);
if (FAILED(hr))
{
wprintf(L" FAILED (%x)\n", hr);
return 1;
}
break;
}
default:
{
std::vector<Image> imageArray;

View File

@ -101,6 +101,8 @@ enum OPTIONS
OPT_COLORKEY,
OPT_TONEMAP,
OPT_X2_BIAS,
OPT_PRESERVE_ALPHA_COVERAGE,
OPT_INVERT_Y,
OPT_FILELIST,
OPT_ROTATE_COLOR,
OPT_PAPER_WHITE_NITS,
@ -186,6 +188,8 @@ const SValue g_pOptions[] =
{ L"c", OPT_COLORKEY },
{ L"tonemap", OPT_TONEMAP },
{ L"x2bias", OPT_X2_BIAS },
{ L"keepcoverage", OPT_PRESERVE_ALPHA_COVERAGE },
{ L"inverty", OPT_INVERT_Y },
{ L"flist", OPT_FILELIST },
{ L"rotatecolor", OPT_ROTATE_COLOR },
{ L"nits", OPT_PAPER_WHITE_NITS },
@ -757,6 +761,8 @@ namespace
wprintf(L" -nits <value> paper-white value in nits to use for HDR10 (def: 200.0)\n");
wprintf(L" -tonemap Apply a tonemap operator based on maximum luminance\n");
wprintf(L" -x2bias Enable *2 - 1 conversion cases for unorm/pos-only-float\n");
wprintf(L" -keepcoverage <ref> Preserve alpha coverage in generated mips for alpha test ref\n");
wprintf(L" -inverty Invert Y (i.e. green) channel values\n");
wprintf(L" -flist <filename> use text file with a list of input files (one per line)\n");
wprintf(L"\n <format>: ");
@ -1121,6 +1127,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
DWORD colorKey = 0;
DWORD dwRotateColor = 0;
float paperWhiteNits = 200.f;
float preserveAlphaCoverageRef = 0.0f;
wchar_t szPrefix[MAX_PATH];
wchar_t szSuffix[MAX_PATH];
@ -1188,6 +1195,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_FILELIST:
case OPT_ROTATE_COLOR:
case OPT_PAPER_WHITE_NITS:
case OPT_PRESERVE_ALPHA_COVERAGE:
if (!*pValue)
{
if ((iArg + 1 >= argc))
@ -1574,15 +1582,27 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_PAPER_WHITE_NITS:
if (swscanf_s(pValue, L"%f", &paperWhiteNits) != 1)
{
wprintf(L"Invalid value specified with -nits (%ls)\n", pValue);
wprintf(L"\n");
wprintf(L"Invalid value specified with -nits (%ls)\n\n", pValue);
PrintUsage();
return 1;
}
else if (paperWhiteNits > 10000.f || paperWhiteNits <= 0.f)
{
wprintf(L"-nits (%ls) parameter must be between 0 and 10000\n", pValue);
wprintf(L"\n");
wprintf(L"-nits (%ls) parameter must be between 0 and 10000\n\n", pValue);
return 1;
}
break;
case OPT_PRESERVE_ALPHA_COVERAGE:
if (swscanf_s(pValue, L"%f", &preserveAlphaCoverageRef) != 1)
{
wprintf(L"Invalid value specified with -keepcoverage (%ls)\n\n", pValue);
PrintUsage();
return 1;
}
else if (preserveAlphaCoverageRef < 0.0f || preserveAlphaCoverageRef > 1.0f)
{
wprintf(L"-keepcoverage (%ls) parameter must be between 0.0 and 1.0\n\n", pValue);
return 1;
}
break;
@ -1660,6 +1680,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
// Convert images
bool nonpow2warn = false;
bool non4bc = false;
bool preserveAlphaCoverage = false;
ComPtr<ID3D11Device> pDevice;
for (auto pConv = conversion.begin(); pConv != conversion.end(); ++pConv)
@ -2483,6 +2504,60 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
cimage.reset();
}
// --- Invert Y Channel --------------------------------------------------------
if (dwOptions & (DWORD64(1) << OPT_INVERT_Y))
{
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),
[&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t width, size_t y)
{
static const XMVECTORU32 s_selecty = { { { XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0 } } };
UNREFERENCED_PARAMETER(y);
for (size_t j = 0; j < width; ++j)
{
XMVECTOR value = inPixels[j];
XMVECTOR inverty = XMVectorSubtract(g_XMOne, value);
outPixels[j] = XMVectorSelect(value, inverty, s_selecty);
}
}, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [inverty] (%x)\n", hr);
return 1;
}
auto& tinfo = timage->GetMetadata();
tinfo;
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.format == tinfo.format);
assert(info.dimension == tinfo.dimension);
image.swap(timage);
cimage.reset();
}
// --- Determine whether preserve alpha coverage is required (if requested) ----
if (preserveAlphaCoverageRef > 0.0f && HasAlpha(info.format) && !image->IsAlphaAllOpaque())
{
preserveAlphaCoverage = true;
}
// --- Generate mips -----------------------------------------------------------
DWORD dwFilter3D = dwFilter;
if (!ispow2(info.width) || !ispow2(info.height) || !ispow2(info.depth))
@ -2499,9 +2574,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
}
}
if ((!tMips || info.mipLevels != tMips) && (info.mipLevels != 1))
if ((!tMips || info.mipLevels != tMips || preserveAlphaCoverage) && (info.mipLevels != 1))
{
// Mips generation only works on a single base image, so strip off existing mip levels
// Also required for preserve alpha coverage so that existing mips are regenerated
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
@ -2627,6 +2704,52 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
cimage.reset();
}
// --- Preserve mipmap alpha coverage (if requested) ---------------------------
if (preserveAlphaCoverage && info.mipLevels != 1 && (info.dimension != TEX_DIMENSION_TEXTURE3D))
{
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
hr = timage->Initialize(image->GetMetadata());
if (FAILED(hr))
{
wprintf(L" FAILED [keepcoverage] (%x)\n", hr);
return 1;
}
const size_t items = image->GetMetadata().arraySize;
for (size_t item = 0; item < items; ++item)
{
auto img = image->GetImage(0, item, 0);
assert(img);
hr = ScaleMipMapsAlphaForCoverage(img, info.mipLevels, info, item, preserveAlphaCoverageRef, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [keepcoverage] (%x)\n", hr);
return 1;
}
}
auto& tinfo = timage->GetMetadata();
tinfo;
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);
cimage.reset();
}
// --- Premultiplied alpha (if requested) --------------------------------------
if ((dwOptions & (DWORD64(1) << OPT_PREMUL_ALPHA))
&& HasAlpha(info.format)