2016-08-22 18:26:36 +00:00
//--------------------------------------------------------------------------------------
// File: Texassemble.cpp
//
2016-09-11 03:43:33 +00:00
// DirectX Texture assembler for cube maps, volume maps, and arrays
2016-08-22 18:26:36 +00:00
//
2021-02-27 06:59:42 +00:00
// Copyright (c) Microsoft Corporation.
2018-02-24 06:24:46 +00:00
// Licensed under the MIT License.
2017-02-26 07:57:13 +00:00
//
// http://go.microsoft.com/fwlink/?LinkId=248926
2016-08-22 18:26:36 +00:00
//--------------------------------------------------------------------------------------
2016-09-11 03:43:33 +00:00
# pragma warning(push)
# pragma warning(disable : 4005)
2016-08-22 18:26:36 +00:00
# define WIN32_LEAN_AND_MEAN
# define NOMINMAX
2016-09-11 03:43:33 +00:00
# define NODRAWTEXT
# define NOGDI
# define NOMCX
# define NOSERVICE
# define NOHELP
# pragma warning(pop)
2016-08-22 18:26:36 +00:00
2021-06-08 22:00:22 +00:00
# include <algorithm>
2020-12-30 02:04:51 +00:00
# include <cassert>
# include <cstddef>
# include <cstdio>
# include <cstdlib>
2021-01-07 08:43:18 +00:00
# include <cwchar>
2021-06-08 22:00:22 +00:00
# include <cwctype>
2017-09-19 18:13:34 +00:00
# include <fstream>
2021-01-02 22:37:52 +00:00
# include <iterator>
2021-04-28 21:33:45 +00:00
# include <list>
# include <locale>
2016-08-22 18:26:36 +00:00
# include <memory>
2021-01-17 19:59:46 +00:00
# include <new>
2021-06-08 22:00:22 +00:00
# include <set>
# include <string>
2021-10-17 18:57:07 +00:00
# include <tuple>
2020-12-30 02:04:51 +00:00
# include <utility>
2016-08-22 18:26:36 +00:00
# include <vector>
2018-02-09 22:32:57 +00:00
# include <wrl/client.h>
2016-08-22 18:26:36 +00:00
# include <dxgiformat.h>
2018-02-09 22:32:57 +00:00
# include <DirectXPackedVector.h>
# include <wincodec.h>
2019-10-24 23:55:13 +00:00
# pragma warning(disable : 4619 4616 26812)
2019-04-17 00:38:37 +00:00
# include "DirectXTex.h"
2016-08-22 18:26:36 +00:00
2016-10-02 19:44:07 +00:00
//Uncomment to add support for OpenEXR (.exr)
//#define USE_OPENEXR
# ifdef USE_OPENEXR
// See <https://github.com/Microsoft/DirectXTex/wiki/Adding-OpenEXR> for details
# include "DirectXTexEXR.h"
# endif
2016-08-22 18:26:36 +00:00
using namespace DirectX ;
2018-02-09 22:32:57 +00:00
using Microsoft : : WRL : : ComPtr ;
2016-08-22 18:26:36 +00:00
2020-07-01 08:37:13 +00:00
namespace
2016-08-22 18:26:36 +00:00
{
2021-10-17 00:31:17 +00:00
enum COMMANDS : uint32_t
2020-07-01 08:37:13 +00:00
{
CMD_CUBE = 1 ,
CMD_VOLUME ,
CMD_ARRAY ,
CMD_CUBEARRAY ,
CMD_H_CROSS ,
CMD_V_CROSS ,
CMD_H_STRIP ,
CMD_V_STRIP ,
CMD_MERGE ,
CMD_GIF ,
CMD_ARRAY_STRIP ,
CMD_MAX
} ;
2016-08-22 18:26:36 +00:00
2021-04-25 02:57:56 +00:00
enum OPTIONS : uint32_t
2020-07-01 08:37:13 +00:00
{
OPT_RECURSIVE = 1 ,
2020-07-09 20:59:11 +00:00
OPT_FILELIST ,
2020-07-01 08:37:13 +00:00
OPT_WIDTH ,
OPT_HEIGHT ,
OPT_FORMAT ,
OPT_FILTER ,
OPT_SRGBI ,
OPT_SRGBO ,
OPT_SRGB ,
OPT_OUTPUTFILE ,
OPT_TOLOWER ,
OPT_OVERWRITE ,
OPT_USE_DX10 ,
OPT_NOLOGO ,
OPT_SEPALPHA ,
OPT_NO_WIC ,
OPT_DEMUL_ALPHA ,
OPT_TA_WRAP ,
OPT_TA_MIRROR ,
2020-07-09 20:59:11 +00:00
OPT_FEATURE_LEVEL ,
2020-07-01 08:37:13 +00:00
OPT_TONEMAP ,
OPT_GIF_BGCOLOR ,
2021-01-10 00:47:58 +00:00
OPT_SWIZZLE ,
2021-03-04 08:21:44 +00:00
OPT_STRIP_MIPS ,
2020-07-01 08:37:13 +00:00
OPT_MAX
} ;
2016-08-22 18:26:36 +00:00
2021-04-25 02:57:56 +00:00
static_assert ( OPT_MAX < = 32 , " dwOptions is a unsigned int bitfield " ) ;
2016-08-22 18:26:36 +00:00
2020-07-01 08:37:13 +00:00
struct SConversion
{
wchar_t szSrc [ MAX_PATH ] ;
} ;
struct SValue
{
2021-04-25 02:57:56 +00:00
const wchar_t * name ;
uint32_t value ;
2020-07-01 08:37:13 +00:00
} ;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
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 } ,
{ L " array-strip " , CMD_ARRAY_STRIP } ,
{ nullptr , 0 }
} ;
const SValue g_pOptions [ ] =
{
{ L " r " , OPT_RECURSIVE } ,
2020-07-09 20:59:11 +00:00
{ L " flist " , OPT_FILELIST } ,
2020-07-01 08:37:13 +00:00
{ 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 " l " , OPT_TOLOWER } ,
{ L " y " , OPT_OVERWRITE } ,
{ L " dx10 " , OPT_USE_DX10 } ,
{ L " nologo " , OPT_NOLOGO } ,
{ L " sepalpha " , OPT_SEPALPHA } ,
{ L " nowic " , OPT_NO_WIC } ,
{ L " alpha " , OPT_DEMUL_ALPHA } ,
{ L " wrap " , OPT_TA_WRAP } ,
{ L " mirror " , OPT_TA_MIRROR } ,
2020-07-09 20:59:11 +00:00
{ L " fl " , OPT_FEATURE_LEVEL } ,
2020-07-01 08:37:13 +00:00
{ L " tonemap " , OPT_TONEMAP } ,
{ L " bgcolor " , OPT_GIF_BGCOLOR } ,
2021-01-10 00:47:58 +00:00
{ L " swizzle " , OPT_SWIZZLE } ,
2021-03-04 08:21:44 +00:00
{ L " stripmips " , OPT_STRIP_MIPS } ,
2020-07-01 08:37:13 +00:00
{ nullptr , 0 }
} ;
2016-08-22 18:26:36 +00:00
2020-05-21 01:18:24 +00:00
# define DEFFMT(fmt) { L## #fmt, DXGI_FORMAT_ ## fmt }
2016-08-22 18:26:36 +00:00
2020-07-01 08:37:13 +00:00
const SValue g_pFormats [ ] =
{
// List does not include _TYPELESS or depth/stencil formats
DEFFMT ( R32G32B32A32_FLOAT ) ,
DEFFMT ( R32G32B32A32_UINT ) ,
DEFFMT ( R32G32B32A32_SINT ) ,
DEFFMT ( R32G32B32_FLOAT ) ,
DEFFMT ( R32G32B32_UINT ) ,
DEFFMT ( R32G32B32_SINT ) ,
DEFFMT ( R16G16B16A16_FLOAT ) ,
DEFFMT ( R16G16B16A16_UNORM ) ,
DEFFMT ( R16G16B16A16_UINT ) ,
DEFFMT ( R16G16B16A16_SNORM ) ,
DEFFMT ( R16G16B16A16_SINT ) ,
DEFFMT ( R32G32_FLOAT ) ,
DEFFMT ( R32G32_UINT ) ,
DEFFMT ( R32G32_SINT ) ,
DEFFMT ( R10G10B10A2_UNORM ) ,
DEFFMT ( R10G10B10A2_UINT ) ,
DEFFMT ( R11G11B10_FLOAT ) ,
DEFFMT ( R8G8B8A8_UNORM ) ,
DEFFMT ( R8G8B8A8_UNORM_SRGB ) ,
DEFFMT ( R8G8B8A8_UINT ) ,
DEFFMT ( R8G8B8A8_SNORM ) ,
DEFFMT ( R8G8B8A8_SINT ) ,
DEFFMT ( R16G16_FLOAT ) ,
DEFFMT ( R16G16_UNORM ) ,
DEFFMT ( R16G16_UINT ) ,
DEFFMT ( R16G16_SNORM ) ,
DEFFMT ( R16G16_SINT ) ,
DEFFMT ( R32_FLOAT ) ,
DEFFMT ( R32_UINT ) ,
DEFFMT ( R32_SINT ) ,
DEFFMT ( R8G8_UNORM ) ,
DEFFMT ( R8G8_UINT ) ,
DEFFMT ( R8G8_SNORM ) ,
DEFFMT ( R8G8_SINT ) ,
DEFFMT ( R16_FLOAT ) ,
DEFFMT ( R16_UNORM ) ,
DEFFMT ( R16_UINT ) ,
DEFFMT ( R16_SNORM ) ,
DEFFMT ( R16_SINT ) ,
DEFFMT ( R8_UNORM ) ,
DEFFMT ( R8_UINT ) ,
DEFFMT ( R8_SNORM ) ,
DEFFMT ( R8_SINT ) ,
DEFFMT ( A8_UNORM ) ,
//DEFFMT(R1_UNORM)
DEFFMT ( R9G9B9E5_SHAREDEXP ) ,
DEFFMT ( R8G8_B8G8_UNORM ) ,
DEFFMT ( G8R8_G8B8_UNORM ) ,
DEFFMT ( B5G6R5_UNORM ) ,
DEFFMT ( B5G5R5A1_UNORM ) ,
// DXGI 1.1 formats
DEFFMT ( B8G8R8A8_UNORM ) ,
DEFFMT ( B8G8R8X8_UNORM ) ,
DEFFMT ( R10G10B10_XR_BIAS_A2_UNORM ) ,
DEFFMT ( B8G8R8A8_UNORM_SRGB ) ,
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 }
} ;
const SValue g_pFormatAliases [ ] =
{
{ L " RGBA " , DXGI_FORMAT_R8G8B8A8_UNORM } ,
{ L " BGRA " , DXGI_FORMAT_B8G8R8A8_UNORM } ,
2021-06-03 01:12:59 +00:00
{ L " BGR " , DXGI_FORMAT_B8G8R8X8_UNORM } ,
2018-02-22 19:57:44 +00:00
2020-07-01 08:37:13 +00:00
{ L " FP16 " , DXGI_FORMAT_R16G16B16A16_FLOAT } ,
{ L " FP32 " , DXGI_FORMAT_R32G32B32A32_FLOAT } ,
2018-02-22 08:17:49 +00:00
2020-07-01 08:37:13 +00:00
{ nullptr , DXGI_FORMAT_UNKNOWN }
} ;
2018-02-22 08:17:49 +00:00
2020-07-01 08:37:13 +00:00
const SValue g_pFilters [ ] =
{
{ L " POINT " , TEX_FILTER_POINT } ,
{ L " LINEAR " , TEX_FILTER_LINEAR } ,
{ L " CUBIC " , TEX_FILTER_CUBIC } ,
{ L " FANT " , TEX_FILTER_FANT } ,
{ L " BOX " , TEX_FILTER_BOX } ,
{ L " TRIANGLE " , TEX_FILTER_TRIANGLE } ,
{ L " POINT_DITHER " , TEX_FILTER_POINT | TEX_FILTER_DITHER } ,
{ L " LINEAR_DITHER " , TEX_FILTER_LINEAR | TEX_FILTER_DITHER } ,
{ L " CUBIC_DITHER " , TEX_FILTER_CUBIC | TEX_FILTER_DITHER } ,
{ L " FANT_DITHER " , TEX_FILTER_FANT | TEX_FILTER_DITHER } ,
{ L " BOX_DITHER " , TEX_FILTER_BOX | TEX_FILTER_DITHER } ,
{ L " TRIANGLE_DITHER " , TEX_FILTER_TRIANGLE | TEX_FILTER_DITHER } ,
{ L " POINT_DITHER_DIFFUSION " , TEX_FILTER_POINT | TEX_FILTER_DITHER_DIFFUSION } ,
{ L " LINEAR_DITHER_DIFFUSION " , TEX_FILTER_LINEAR | TEX_FILTER_DITHER_DIFFUSION } ,
{ L " CUBIC_DITHER_DIFFUSION " , TEX_FILTER_CUBIC | TEX_FILTER_DITHER_DIFFUSION } ,
{ L " FANT_DITHER_DIFFUSION " , TEX_FILTER_FANT | TEX_FILTER_DITHER_DIFFUSION } ,
{ L " BOX_DITHER_DIFFUSION " , TEX_FILTER_BOX | TEX_FILTER_DITHER_DIFFUSION } ,
{ L " TRIANGLE_DITHER_DIFFUSION " , TEX_FILTER_TRIANGLE | TEX_FILTER_DITHER_DIFFUSION } ,
{ nullptr , TEX_FILTER_DEFAULT }
} ;
2016-08-22 18:26:36 +00:00
2019-09-14 00:31:09 +00:00
# define CODEC_DDS 0xFFFF0001
2016-09-24 08:06:54 +00:00
# define CODEC_TGA 0xFFFF0002
# define CODEC_HDR 0xFFFF0005
2019-07-06 06:48:39 +00:00
# ifdef USE_OPENEXR
2016-10-02 19:44:07 +00:00
# define CODEC_EXR 0xFFFF0006
2019-07-06 06:48:39 +00:00
# endif
2016-09-24 08:06:54 +00:00
2020-07-01 08:37:13 +00:00
const 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 } ,
# ifdef USE_OPENEXR
{ L " EXR " , CODEC_EXR } ,
# endif
{ nullptr , CODEC_DDS }
} ;
2020-07-09 20:59:11 +00:00
const SValue g_pFeatureLevels [ ] = // valid feature levels for -fl for maximimum size
{
{ L " 9.1 " , 2048 } ,
{ L " 9.2 " , 2048 } ,
{ L " 9.3 " , 4096 } ,
{ L " 10.0 " , 8192 } ,
{ L " 10.1 " , 8192 } ,
{ L " 11.0 " , 16384 } ,
{ L " 11.1 " , 16384 } ,
{ L " 12.0 " , 16384 } ,
{ L " 12.1 " , 16384 } ,
2021-10-29 22:46:20 +00:00
{ L " 12.2 " , 16384 } ,
2020-07-09 20:59:11 +00:00
{ nullptr , 0 } ,
} ;
const SValue g_pFeatureLevelsCube [ ] = // valid feature levels for -fl for maximum cubemap size
{
{ L " 9.1 " , 512 } ,
{ L " 9.2 " , 512 } ,
{ L " 9.3 " , 4096 } ,
{ L " 10.0 " , 8192 } ,
{ L " 10.1 " , 8192 } ,
{ L " 11.0 " , 16384 } ,
{ L " 11.1 " , 16384 } ,
{ L " 12.0 " , 16384 } ,
{ L " 12.1 " , 16384 } ,
2021-10-29 22:46:20 +00:00
{ L " 12.2 " , 16384 } ,
2020-07-09 20:59:11 +00:00
{ nullptr , 0 } ,
} ;
const SValue g_pFeatureLevelsArray [ ] = // valid feature levels for -fl for maximum array size
{
{ L " 9.1 " , 1 } ,
{ L " 9.2 " , 1 } ,
{ L " 9.3 " , 1 } ,
{ L " 10.0 " , 512 } ,
{ L " 10.1 " , 512 } ,
{ L " 11.0 " , 2048 } ,
{ L " 11.1 " , 2048 } ,
{ L " 12.0 " , 2048 } ,
{ L " 12.1 " , 2048 } ,
2021-10-29 22:46:20 +00:00
{ L " 12.2 " , 2048 } ,
2020-07-09 20:59:11 +00:00
{ nullptr , 0 } ,
} ;
const SValue g_pFeatureLevelsVolume [ ] = // valid feature levels for -fl for maximum depth size
{
{ L " 9.1 " , 256 } ,
{ L " 9.2 " , 256 } ,
{ L " 9.3 " , 256 } ,
{ L " 10.0 " , 2048 } ,
{ L " 10.1 " , 2048 } ,
{ L " 11.0 " , 2048 } ,
{ L " 11.1 " , 2048 } ,
{ L " 12.0 " , 2048 } ,
{ L " 12.1 " , 2048 } ,
2021-10-29 22:46:20 +00:00
{ L " 12.2 " , 2048 } ,
2020-07-09 20:59:11 +00:00
{ nullptr , 0 } ,
} ;
2020-07-01 08:37:13 +00:00
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
HRESULT LoadAnimatedGif ( const wchar_t * szFile ,
std : : vector < std : : unique_ptr < ScratchImage > > & loadedImages ,
bool usebgcolor ) ;
2016-09-24 08:06:54 +00:00
2016-08-22 18:26:36 +00:00
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
2016-09-12 23:39:26 +00:00
namespace
{
2020-06-05 03:07:21 +00:00
inline HANDLE safe_handle ( HANDLE h ) noexcept { return ( h = = INVALID_HANDLE_VALUE ) ? nullptr : h ; }
2016-09-13 04:54:08 +00:00
2020-06-05 03:07:21 +00:00
struct find_closer { void operator ( ) ( HANDLE h ) noexcept { assert ( h ! = INVALID_HANDLE_VALUE ) ; if ( h ) FindClose ( h ) ; } } ;
2016-09-13 04:54:08 +00:00
2020-01-19 09:36:52 +00:00
using ScopedFindHandle = std : : unique_ptr < void , find_closer > ;
2016-09-13 04:54:08 +00:00
2019-07-06 06:48:39 +00:00
# ifdef _PREFAST_
2016-08-22 18:26:36 +00:00
# pragma prefast(disable : 26018, "Only used with static internal arrays")
2019-07-06 06:48:39 +00:00
# endif
2016-08-22 18:26:36 +00:00
2021-04-25 02:57:56 +00:00
uint32_t LookupByName ( const wchar_t * pName , const SValue * pArray )
2016-08-22 18:26:36 +00:00
{
2021-04-25 02:57:56 +00:00
while ( pArray - > name )
2016-09-12 23:39:26 +00:00
{
2021-04-25 02:57:56 +00:00
if ( ! _wcsicmp ( pName , pArray - > name ) )
return pArray - > value ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
pArray + + ;
}
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
return 0 ;
}
2016-08-22 18:26:36 +00:00
2016-09-13 04:54:08 +00:00
void SearchForFiles ( const wchar_t * path , std : : list < SConversion > & files , bool recursive )
{
// Process files
2019-02-07 22:52:57 +00:00
WIN32_FIND_DATAW findData = { } ;
2016-09-13 04:54:08 +00:00
ScopedFindHandle hFile ( safe_handle ( FindFirstFileExW ( path ,
FindExInfoBasic , & findData ,
FindExSearchNameMatch , nullptr ,
FIND_FIRST_EX_LARGE_FETCH ) ) ) ;
if ( hFile )
{
for ( ; ; )
{
if ( ! ( findData . dwFileAttributes & ( FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY ) ) )
{
wchar_t drive [ _MAX_DRIVE ] = { } ;
wchar_t dir [ _MAX_DIR ] = { } ;
_wsplitpath_s ( path , drive , _MAX_DRIVE , dir , _MAX_DIR , nullptr , 0 , nullptr , 0 ) ;
2021-01-09 20:44:59 +00:00
SConversion conv = { } ;
2016-09-13 04:54:08 +00:00
_wmakepath_s ( conv . szSrc , drive , dir , findData . cFileName , nullptr ) ;
files . push_back ( conv ) ;
}
2019-02-07 22:52:57 +00:00
if ( ! FindNextFileW ( hFile . get ( ) , & findData ) )
2016-09-13 04:54:08 +00:00
break ;
}
}
// Process directories
if ( recursive )
{
wchar_t searchDir [ MAX_PATH ] = { } ;
{
wchar_t drive [ _MAX_DRIVE ] = { } ;
wchar_t dir [ _MAX_DIR ] = { } ;
_wsplitpath_s ( path , drive , _MAX_DRIVE , dir , _MAX_DIR , nullptr , 0 , nullptr , 0 ) ;
_wmakepath_s ( searchDir , drive , dir , L " * " , nullptr ) ;
}
hFile . reset ( safe_handle ( FindFirstFileExW ( searchDir ,
FindExInfoBasic , & findData ,
FindExSearchLimitToDirectories , nullptr ,
FIND_FIRST_EX_LARGE_FETCH ) ) ) ;
if ( ! hFile )
return ;
for ( ; ; )
{
if ( findData . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
if ( findData . cFileName [ 0 ] ! = L ' . ' )
{
wchar_t subdir [ MAX_PATH ] = { } ;
{
wchar_t drive [ _MAX_DRIVE ] = { } ;
wchar_t dir [ _MAX_DIR ] = { } ;
wchar_t fname [ _MAX_FNAME ] = { } ;
wchar_t ext [ _MAX_FNAME ] = { } ;
_wsplitpath_s ( path , drive , dir , fname , ext ) ;
wcscat_s ( dir , findData . cFileName ) ;
_wmakepath_s ( subdir , drive , dir , fname , ext ) ;
}
SearchForFiles ( subdir , files , recursive ) ;
}
}
2019-02-07 22:52:57 +00:00
if ( ! FindNextFileW ( hFile . get ( ) , & findData ) )
2016-09-13 04:54:08 +00:00
break ;
}
}
}
2021-06-08 22:00:22 +00:00
void ProcessFileList ( std : : wifstream & inFile , std : : list < SConversion > & files )
{
std : : list < SConversion > flist ;
std : : set < std : : wstring > excludes ;
wchar_t fname [ 1024 ] = { } ;
for ( ; ; )
{
inFile > > fname ;
if ( ! inFile )
break ;
if ( * fname = = L ' # ' )
{
// Comment
}
else if ( * fname = = L ' - ' )
{
if ( flist . empty ( ) )
{
wprintf ( L " WARNING: Ignoring the line '%ls' in -flist \n " , fname ) ;
}
else
{
if ( wcspbrk ( fname , L " ?* " ) ! = nullptr )
{
std : : list < SConversion > removeFiles ;
SearchForFiles ( & fname [ 1 ] , removeFiles , false ) ;
for ( auto it : removeFiles )
{
_wcslwr_s ( it . szSrc ) ;
excludes . insert ( it . szSrc ) ;
}
}
else
{
std : : wstring name = ( fname + 1 ) ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , towlower ) ;
excludes . insert ( name ) ;
}
}
}
else if ( wcspbrk ( fname , L " ?* " ) ! = nullptr )
{
SearchForFiles ( fname , flist , false ) ;
}
else
{
SConversion conv = { } ;
wcscpy_s ( conv . szSrc , MAX_PATH , fname ) ;
flist . push_back ( conv ) ;
}
inFile . ignore ( 1000 , ' \n ' ) ;
}
inFile . close ( ) ;
if ( ! excludes . empty ( ) )
{
// Remove any excluded files
for ( auto it = flist . begin ( ) ; it ! = flist . end ( ) ; )
{
std : : wstring name = it - > szSrc ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , towlower ) ;
auto item = it ;
+ + it ;
if ( excludes . find ( name ) ! = excludes . end ( ) )
{
flist . erase ( item ) ;
}
}
}
if ( flist . empty ( ) )
{
wprintf ( L " WARNING: No file names found in -flist \n " ) ;
}
else
{
files . splice ( files . end ( ) , flist ) ;
}
}
2016-09-12 23:39:26 +00:00
void PrintFormat ( DXGI_FORMAT Format )
2016-08-22 18:26:36 +00:00
{
2021-04-25 02:57:56 +00:00
for ( auto pFormat = g_pFormats ; pFormat - > name ; pFormat + + )
2016-08-22 18:26:36 +00:00
{
2021-04-25 02:57:56 +00:00
if ( static_cast < DXGI_FORMAT > ( pFormat - > value ) = = Format )
2016-09-12 23:39:26 +00:00
{
2021-04-25 02:57:56 +00:00
wprintf ( L " %ls " , pFormat - > name ) ;
2016-09-12 23:39:26 +00:00
break ;
}
2016-08-22 18:26:36 +00:00
}
}
2016-09-12 23:39:26 +00:00
void PrintInfo ( const TexMetadata & info )
{
2018-05-02 00:34:54 +00:00
wprintf ( L " (%zux%zu " , info . width , info . height ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
if ( TEX_DIMENSION_TEXTURE3D = = info . dimension )
2018-05-02 00:34:54 +00:00
wprintf ( L " x%zu " , info . depth ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
if ( info . mipLevels > 1 )
2018-05-02 00:34:54 +00:00
wprintf ( L " ,%zu " , info . mipLevels ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
if ( info . arraySize > 1 )
2018-05-02 00:34:54 +00:00
wprintf ( L " ,%zu " , info . arraySize ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
wprintf ( L " " ) ;
PrintFormat ( info . format ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
switch ( info . dimension )
2016-08-22 18:26:36 +00:00
{
2016-09-12 23:39:26 +00:00
case TEX_DIMENSION_TEXTURE1D :
2019-11-15 08:13:05 +00:00
wprintf ( L " %ls " , ( info . arraySize > 1 ) ? L " 1DArray " : L " 1D " ) ;
2016-09-12 23:39:26 +00:00
break ;
case TEX_DIMENSION_TEXTURE2D :
if ( info . IsCubemap ( ) )
{
2019-11-15 08:13:05 +00:00
wprintf ( L " %ls " , ( info . arraySize > 6 ) ? L " CubeArray " : L " Cube " ) ;
2016-09-12 23:39:26 +00:00
}
else
{
2019-11-15 08:13:05 +00:00
wprintf ( L " %ls " , ( info . arraySize > 1 ) ? L " 2DArray " : L " 2D " ) ;
2016-09-12 23:39:26 +00:00
}
break ;
case TEX_DIMENSION_TEXTURE3D :
wprintf ( L " 3D " ) ;
break ;
2016-08-22 18:26:36 +00:00
}
2016-09-24 08:06:54 +00:00
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 ;
2019-07-06 06:48:39 +00:00
case TEX_ALPHA_MODE_CUSTOM :
wprintf ( L " \x0e0 :Custom " ) ;
break ;
case TEX_ALPHA_MODE_UNKNOWN :
break ;
2016-09-24 08:06:54 +00:00
}
2016-09-12 23:39:26 +00:00
wprintf ( L " ) " ) ;
2016-08-22 18:26:36 +00:00
}
2016-09-25 21:09:14 +00:00
void PrintList ( size_t cch , const SValue * pValue )
2016-08-22 18:26:36 +00:00
{
2021-04-25 02:57:56 +00:00
while ( pValue - > name )
2016-08-22 18:26:36 +00:00
{
2022-03-01 22:31:55 +00:00
const size_t cchName = wcslen ( pValue - > name ) ;
2016-09-12 23:39:26 +00:00
if ( cch + cchName + 2 > = 80 )
{
wprintf ( L " \n " ) ;
cch = 6 ;
}
2021-04-25 02:57:56 +00:00
wprintf ( L " %ls " , pValue - > name ) ;
2016-09-12 23:39:26 +00:00
cch + = cchName + 2 ;
pValue + + ;
2016-08-22 18:26:36 +00:00
}
2016-09-12 23:39:26 +00:00
wprintf ( L " \n " ) ;
2016-08-22 18:26:36 +00:00
}
2016-09-12 23:39:26 +00:00
void PrintLogo ( )
{
2020-08-15 22:57:39 +00:00
wchar_t version [ 32 ] = { } ;
wchar_t appName [ _MAX_PATH ] = { } ;
2021-01-02 20:44:35 +00:00
if ( GetModuleFileNameW ( nullptr , appName , static_cast < DWORD > ( std : : size ( appName ) ) ) )
2020-08-15 22:57:39 +00:00
{
2022-03-01 22:31:55 +00:00
const DWORD size = GetFileVersionInfoSizeW ( appName , nullptr ) ;
2020-08-15 22:57:39 +00:00
if ( size > 0 )
{
auto verInfo = std : : make_unique < uint8_t [ ] > ( size ) ;
if ( GetFileVersionInfoW ( appName , 0 , size , verInfo . get ( ) ) )
{
LPVOID lpstr = nullptr ;
UINT strLen = 0 ;
if ( VerQueryValueW ( verInfo . get ( ) , L " \\ StringFileInfo \\ 040904B0 \\ ProductVersion " , & lpstr , & strLen ) )
{
wcsncpy_s ( version , reinterpret_cast < const wchar_t * > ( lpstr ) , strLen ) ;
}
}
}
}
if ( ! * version | | wcscmp ( version , L " 1.0.0.0 " ) = = 0 )
{
swprintf_s ( version , L " %03d (library) " , DIRECTX_TEX_VERSION ) ;
}
wprintf ( L " Microsoft (R) DirectX Texture Assembler [DirectXTex] Version %ls \n " , version ) ;
2021-02-27 06:59:42 +00:00
wprintf ( L " Copyright (C) Microsoft Corp. \n " ) ;
2016-09-14 05:08:15 +00:00
# ifdef _DEBUG
wprintf ( L " *** Debug build *** \n " ) ;
# endif
2016-09-12 23:39:26 +00:00
wprintf ( L " \n " ) ;
}
2016-08-22 18:26:36 +00:00
2021-04-01 07:59:57 +00:00
const wchar_t * GetErrorDesc ( HRESULT hr )
{
static wchar_t desc [ 1024 ] = { } ;
LPWSTR errorText = nullptr ;
2022-03-01 22:31:55 +00:00
const DWORD result = FormatMessageW ( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER ,
2021-06-02 21:36:31 +00:00
nullptr , static_cast < DWORD > ( hr ) ,
2021-04-01 07:59:57 +00:00
MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , reinterpret_cast < LPWSTR > ( & errorText ) , 0 , nullptr ) ;
* desc = 0 ;
if ( result > 0 & & errorText )
{
swprintf_s ( desc , L " : %ls " , errorText ) ;
size_t len = wcslen ( desc ) ;
2022-03-02 22:25:27 +00:00
if ( len > = 1 )
2021-04-01 07:59:57 +00:00
{
desc [ len - 1 ] = 0 ;
}
if ( errorText )
LocalFree ( errorText ) ;
}
return desc ;
}
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
void PrintUsage ( )
{
PrintLogo ( ) ;
2016-08-22 18:26:36 +00:00
2016-09-24 08:06:54 +00:00
wprintf ( L " Usage: texassemble <command> <options> <files> \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 " ) ;
2018-02-08 02:14:42 +00:00
wprintf ( L " h-strip or v-strip create a strip image from a cubemap \n " ) ;
2019-01-29 00:26:46 +00:00
wprintf ( L " array-strip creates a strip image from a 1D/2D array \n " ) ;
2018-02-09 22:32:57 +00:00
wprintf ( L " merge create texture from rgb image and alpha image \n " ) ;
wprintf ( L " gif create array from animated gif \n \n " ) ;
2016-09-13 04:54:08 +00:00
wprintf ( L " -r wildcard filename search is recursive \n " ) ;
2020-07-09 20:59:11 +00:00
wprintf ( L " -flist <filename> use text file with a list of input files (one per line) \n " ) ;
2016-09-12 23:39:26 +00:00
wprintf ( L " -w <n> width \n " ) ;
wprintf ( L " -h <n> height \n " ) ;
wprintf ( L " -f <format> format \n " ) ;
wprintf ( L " -if <filter> image filtering \n " ) ;
2016-09-24 08:06:54 +00:00
wprintf ( L " -srgb{i|o} sRGB {input, output} \n " ) ;
2016-09-12 23:39:26 +00:00
wprintf ( L " -o <filename> output filename \n " ) ;
2020-04-14 00:22:55 +00:00
wprintf ( L " -l force output filename to lower case \n " ) ;
2016-09-24 08:06:54 +00:00
wprintf ( L " -y overwrite existing output file (if any) \n " ) ;
2016-09-12 23:39:26 +00:00
wprintf ( L " -sepalpha resize alpha channel separately from color channels \n " ) ;
2018-08-02 19:31:20 +00:00
wprintf ( L " -nowic Force non-WIC filtering \n " ) ;
2016-09-24 08:06:54 +00:00
wprintf ( L " -wrap, -mirror texture addressing mode (wrap, mirror, or clamp) \n " ) ;
wprintf ( L " -alpha convert premultiplied alpha to straight alpha \n " ) ;
2016-09-12 23:39:26 +00:00
wprintf ( L " -dx10 Force use of 'DX10' extended header \n " ) ;
wprintf ( L " -nologo suppress copyright message \n " ) ;
2020-07-09 20:59:11 +00:00
wprintf ( L " -fl <feature-level> Set maximum feature level target (defaults to 11.0) \n " ) ;
2017-02-26 07:57:13 +00:00
wprintf ( L " -tonemap Apply a tonemap operator based on maximum luminance \n " ) ;
2018-02-09 22:32:57 +00:00
wprintf ( L " \n (gif only) \n " ) ;
wprintf ( L " -bgcolor Use background color instead of transparency \n " ) ;
2021-01-10 00:47:58 +00:00
wprintf ( L " \n (merge only) \n " ) ;
wprintf ( L " -swizzle <rgba> Select channels for merge (defaults to rgbB) \n " ) ;
2021-03-11 04:42:37 +00:00
wprintf ( L " \n (cube, volume, array, cubearray, merge only) \n " ) ;
2021-03-04 08:21:44 +00:00
wprintf ( L " -stripmips Use only base image from input dds files \n " ) ;
2016-09-12 23:39:26 +00:00
2016-09-24 08:06:54 +00:00
wprintf ( L " \n <format>: " ) ;
2016-09-12 23:39:26 +00:00
PrintList ( 13 , g_pFormats ) ;
2018-02-22 08:17:49 +00:00
wprintf ( L " " ) ;
PrintList ( 13 , g_pFormatAliases ) ;
2016-09-12 23:39:26 +00:00
2016-09-24 08:06:54 +00:00
wprintf ( L " \n <filter>: " ) ;
2016-09-12 23:39:26 +00:00
PrintList ( 13 , g_pFilters ) ;
2020-07-09 20:59:11 +00:00
wprintf ( L " \n <feature-level>: " ) ;
PrintList ( 13 , g_pFeatureLevels ) ;
2016-09-12 23:39:26 +00:00
}
2018-02-08 02:14:42 +00:00
2021-04-25 02:57:56 +00:00
HRESULT SaveImageFile ( const Image & img , uint32_t fileType , const wchar_t * szOutputFile )
2018-02-08 02:14:42 +00:00
{
switch ( fileType )
{
case CODEC_DDS :
return SaveToDDSFile ( img , DDS_FLAGS_NONE , szOutputFile ) ;
case CODEC_TGA :
2020-09-30 19:37:49 +00:00
return SaveToTGAFile ( img , TGA_FLAGS_NONE , szOutputFile ) ;
2018-02-08 02:14:42 +00:00
case CODEC_HDR :
return SaveToHDRFile ( img , szOutputFile ) ;
2019-09-14 00:31:09 +00:00
# ifdef USE_OPENEXR
2018-02-08 02:14:42 +00:00
case CODEC_EXR :
return SaveToEXRFile ( img , szOutputFile ) ;
2019-09-14 00:31:09 +00:00
# endif
2018-02-08 02:14:42 +00:00
default :
2022-03-02 22:25:27 +00:00
{
HRESULT hr = SaveToWICFile ( img , WIC_FLAGS_NONE , GetWICCodec ( static_cast < WICCodecs > ( fileType ) ) , szOutputFile ) ;
if ( ( hr = = static_cast < HRESULT > ( 0xc00d5212 ) /* MF_E_TOPO_CODEC_NOT_FOUND */ ) & & ( fileType = = WIC_CODEC_HEIF ) )
{
wprintf ( L " \n INFO: This format requires installing the HEIF Image Extensions - https://aka.ms/heif \n " ) ;
}
return hr ;
}
2018-02-08 02:14:42 +00:00
}
}
2021-01-10 00:47:58 +00:00
2021-02-25 08:57:58 +00:00
bool ParseSwizzleMask (
_In_reads_ ( 4 ) const wchar_t * mask ,
_Out_writes_ ( 4 ) uint32_t * permuteElements ,
_Out_writes_ ( 4 ) uint32_t * zeroElements ,
_Out_writes_ ( 4 ) uint32_t * oneElements )
2021-01-10 00:47:58 +00:00
{
2021-02-25 08:57:58 +00:00
if ( ! mask | | ! permuteElements | | ! zeroElements | | ! oneElements )
2021-01-10 00:47:58 +00:00
return false ;
if ( ! mask [ 0 ] )
return false ;
2021-02-26 04:42:24 +00:00
for ( uint32_t j = 0 ; j < 4 ; + + j )
2021-01-10 00:47:58 +00:00
{
if ( ! mask [ j ] )
break ;
switch ( mask [ j ] )
{
case L ' r ' :
case L ' x ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 0 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' R ' :
case L ' X ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 4 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' g ' :
case L ' y ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 1 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' G ' :
case L ' Y ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 5 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' b ' :
case L ' z ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 2 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' B ' :
case L ' Z ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 6 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' a ' :
case L ' w ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 3 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
2021-01-10 00:47:58 +00:00
break ;
case L ' A ' :
case L ' W ' :
2021-02-26 04:42:24 +00:00
for ( uint32_t k = j ; k < 4 ; + + k )
2021-02-25 08:57:58 +00:00
{
2021-01-10 00:47:58 +00:00
permuteElements [ k ] = 7 ;
2021-02-25 08:57:58 +00:00
zeroElements [ k ] = 0 ;
oneElements [ k ] = 0 ;
}
break ;
case L ' 0 ' :
for ( uint32_t k = j ; k < 4 ; + + k )
{
permuteElements [ k ] = k ;
zeroElements [ k ] = 1 ;
oneElements [ k ] = 0 ;
}
break ;
case L ' 1 ' :
for ( uint32_t k = j ; k < 4 ; + + k )
{
permuteElements [ k ] = k ;
zeroElements [ k ] = 0 ;
oneElements [ k ] = 1 ;
}
2021-01-10 00:47:58 +00:00
break ;
default :
return false ;
}
}
return true ;
}
2016-08-22 18:26:36 +00:00
}
//--------------------------------------------------------------------------------------
// Entry-point
//--------------------------------------------------------------------------------------
2019-07-06 06:48:39 +00:00
# ifdef _PREFAST_
2016-08-22 18:26:36 +00:00
# pragma prefast(disable : 28198, "Command-line tool, frees all memory on exit")
2019-07-06 06:48:39 +00:00
# endif
2016-08-22 18:26:36 +00:00
int __cdecl wmain ( _In_ int argc , _In_z_count_ ( argc ) wchar_t * argv [ ] )
{
// Parameters and defaults
size_t width = 0 ;
2016-09-12 23:39:26 +00:00
size_t height = 0 ;
2016-08-22 18:26:36 +00:00
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN ;
2020-06-01 07:42:02 +00:00
TEX_FILTER_FLAGS dwFilter = TEX_FILTER_DEFAULT ;
TEX_FILTER_FLAGS dwSRGB = TEX_FILTER_DEFAULT ;
TEX_FILTER_FLAGS dwFilterOpts = TEX_FILTER_DEFAULT ;
2021-04-25 02:57:56 +00:00
uint32_t fileType = WIC_CODEC_BMP ;
uint32_t maxSize = 16384 ;
uint32_t maxCube = 16384 ;
uint32_t maxArray = 2048 ;
uint32_t maxVolume = 2048 ;
2016-08-22 18:26:36 +00:00
2021-01-10 00:47:58 +00:00
// DXTex's Open Alpha onto Surface always loaded alpha from the blue channel
uint32_t permuteElements [ 4 ] = { 0 , 1 , 2 , 6 } ;
2021-02-25 08:57:58 +00:00
uint32_t zeroElements [ 4 ] = { } ;
uint32_t oneElements [ 4 ] = { } ;
2021-01-10 00:47:58 +00:00
2018-01-18 23:02:05 +00:00
wchar_t szOutputFile [ MAX_PATH ] = { } ;
2016-08-22 18:26:36 +00:00
2021-04-28 21:33:45 +00:00
// Set locale for output since GetErrorDesc can get localized strings.
std : : locale : : global ( std : : locale ( " " ) ) ;
2016-08-22 18:26:36 +00:00
// Initialize COM (needed for WIC)
HRESULT hr = hr = CoInitializeEx ( nullptr , COINIT_MULTITHREADED ) ;
2016-09-12 23:39:26 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2021-04-01 07:59:57 +00:00
wprintf ( L " Failed to initialize COM (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
// Process command line
2016-09-24 08:06:54 +00:00
if ( argc < 2 )
{
PrintUsage ( ) ;
return 0 ;
}
2022-03-01 22:31:55 +00:00
const uint32_t dwCommand = LookupByName ( argv [ 1 ] , g_pCommands ) ;
2016-09-24 08:06:54 +00:00
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 :
2018-02-08 02:14:42 +00:00
case CMD_MERGE :
2018-02-09 22:32:57 +00:00
case CMD_GIF :
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2016-09-24 08:06:54 +00:00
break ;
default :
2019-01-29 00:26:46 +00:00
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 " ) ;
2016-09-24 08:06:54 +00:00
return 1 ;
}
2021-04-25 02:57:56 +00:00
uint32_t dwOptions = 0 ;
2016-09-25 21:09:14 +00:00
std : : list < SConversion > conversion ;
2016-09-24 08:06:54 +00:00
for ( int iArg = 2 ; iArg < argc ; iArg + + )
2016-08-22 18:26:36 +00:00
{
PWSTR pArg = argv [ iArg ] ;
2016-09-12 23:39:26 +00:00
if ( ( ' - ' = = pArg [ 0 ] ) | | ( ' / ' = = pArg [ 0 ] ) )
2016-08-22 18:26:36 +00:00
{
pArg + + ;
PWSTR pValue ;
2016-09-12 23:39:26 +00:00
for ( pValue = pArg ; * pValue & & ( ' : ' ! = * pValue ) ; pValue + + ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
if ( * pValue )
2016-08-22 18:26:36 +00:00
* pValue + + = 0 ;
2022-03-01 22:31:55 +00:00
const uint32_t dwOption = LookupByName ( pArg , g_pOptions ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
if ( ! dwOption | | ( dwOptions & ( 1 < < dwOption ) ) )
2016-08-22 18:26:36 +00:00
{
PrintUsage ( ) ;
return 1 ;
}
dwOptions | = 1 < < dwOption ;
2016-09-12 23:39:26 +00:00
// Handle options with additional value parameter
switch ( dwOption )
2016-08-22 18:26:36 +00:00
{
2020-07-09 20:59:11 +00:00
case OPT_FILELIST :
2016-09-12 23:39:26 +00:00
case OPT_WIDTH :
case OPT_HEIGHT :
case OPT_FORMAT :
case OPT_FILTER :
case OPT_OUTPUTFILE :
2020-07-09 20:59:11 +00:00
case OPT_FEATURE_LEVEL :
2021-01-10 00:47:58 +00:00
case OPT_SWIZZLE :
2016-09-12 23:39:26 +00:00
if ( ! * pValue )
2016-08-22 18:26:36 +00:00
{
2016-09-12 23:39:26 +00:00
if ( ( iArg + 1 > = argc ) )
2016-08-22 18:26:36 +00:00
{
PrintUsage ( ) ;
return 1 ;
}
iArg + + ;
pValue = argv [ iArg ] ;
}
2019-07-06 06:48:39 +00:00
break ;
default :
break ;
2016-08-22 18:26:36 +00:00
}
2016-09-12 23:39:26 +00:00
switch ( dwOption )
2016-08-22 18:26:36 +00:00
{
case OPT_WIDTH :
2018-05-02 00:34:54 +00:00
if ( swscanf_s ( pValue , L " %zu " , & width ) ! = 1 )
2016-08-22 18:26:36 +00:00
{
2016-09-12 23:39:26 +00:00
wprintf ( L " Invalid value specified with -w (%ls) \n " , pValue ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
break ;
case OPT_HEIGHT :
2018-05-02 00:34:54 +00:00
if ( swscanf_s ( pValue , L " %zu " , & height ) ! = 1 )
2016-08-22 18:26:36 +00:00
{
2016-09-12 23:39:26 +00:00
wprintf ( L " Invalid value specified with -h (%ls) \n " , pValue ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
break ;
case OPT_FORMAT :
2018-02-22 08:17:49 +00:00
format = static_cast < DXGI_FORMAT > ( LookupByName ( pValue , g_pFormats ) ) ;
2016-09-12 23:39:26 +00:00
if ( ! format )
2016-08-22 18:26:36 +00:00
{
2018-02-22 08:17:49 +00:00
format = static_cast < DXGI_FORMAT > ( LookupByName ( pValue , g_pFormatAliases ) ) ;
if ( ! format )
{
wprintf ( L " Invalid value specified with -f (%ls) \n " , pValue ) ;
return 1 ;
}
2016-08-22 18:26:36 +00:00
}
break ;
case OPT_FILTER :
2020-06-01 07:42:02 +00:00
dwFilter = static_cast < TEX_FILTER_FLAGS > ( LookupByName ( pValue , g_pFilters ) ) ;
2016-09-12 23:39:26 +00:00
if ( ! dwFilter )
2016-08-22 18:26:36 +00:00
{
2016-09-12 23:39:26 +00:00
wprintf ( L " Invalid value specified with -if (%ls) \n " , pValue ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
break ;
2016-09-24 08:06:54 +00:00
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 ;
2016-08-22 18:26:36 +00:00
case OPT_SEPALPHA :
dwFilterOpts | = TEX_FILTER_SEPARATE_ALPHA ;
break ;
2018-08-02 19:31:20 +00:00
case OPT_NO_WIC :
dwFilterOpts | = TEX_FILTER_FORCE_NON_WIC ;
break ;
2016-08-22 18:26:36 +00:00
case OPT_OUTPUTFILE :
2016-09-24 08:06:54 +00:00
{
2016-08-22 18:26:36 +00:00
wcscpy_s ( szOutputFile , MAX_PATH , pValue ) ;
2016-09-24 08:06:54 +00:00
2020-07-10 22:39:55 +00:00
wchar_t ext [ _MAX_EXT ] = { } ;
2016-09-24 08:06:54 +00:00
_wsplitpath_s ( szOutputFile , nullptr , 0 , nullptr , 0 , nullptr , 0 , ext , _MAX_EXT ) ;
2018-02-08 02:14:42 +00:00
fileType = LookupByName ( ext , g_pExtFileTypes ) ;
2016-09-24 08:06:54 +00:00
switch ( dwCommand )
{
case CMD_H_CROSS :
case CMD_V_CROSS :
case CMD_H_STRIP :
case CMD_V_STRIP :
2018-02-08 02:14:42 +00:00
case CMD_MERGE :
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2016-09-24 08:06:54 +00:00
break ;
default :
2018-02-08 02:14:42 +00:00
if ( fileType ! = CODEC_DDS )
2016-09-24 08:06:54 +00:00
{
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 ;
2016-08-22 18:26:36 +00:00
break ;
2017-09-19 18:13:34 +00:00
case OPT_FILELIST :
2019-09-14 00:31:09 +00:00
{
std : : wifstream inFile ( pValue ) ;
if ( ! inFile )
2017-09-19 18:13:34 +00:00
{
2019-09-14 00:31:09 +00:00
wprintf ( L " Error opening -flist file %ls \n " , pValue ) ;
return 1 ;
}
2021-10-28 18:12:16 +00:00
inFile . imbue ( std : : locale : : classic ( ) ) ;
2021-06-08 22:00:22 +00:00
ProcessFileList ( inFile , conversion ) ;
2019-09-14 00:31:09 +00:00
}
break ;
2018-02-09 22:32:57 +00:00
2020-07-09 20:59:11 +00:00
case OPT_FEATURE_LEVEL :
maxSize = LookupByName ( pValue , g_pFeatureLevels ) ;
maxCube = LookupByName ( pValue , g_pFeatureLevelsCube ) ;
maxArray = LookupByName ( pValue , g_pFeatureLevelsArray ) ;
maxVolume = LookupByName ( pValue , g_pFeatureLevelsVolume ) ;
if ( ! maxSize | | ! maxCube | | ! maxArray | | ! maxVolume )
{
wprintf ( L " Invalid value specified with -fl (%ls) \n " , pValue ) ;
wprintf ( L " \n " ) ;
PrintUsage ( ) ;
return 1 ;
}
break ;
2018-02-09 22:32:57 +00:00
case OPT_GIF_BGCOLOR :
if ( dwCommand ! = CMD_GIF )
{
wprintf ( L " -bgcolor only applies to gif command \n " ) ;
return 1 ;
}
break ;
2019-07-06 06:48:39 +00:00
2021-01-10 00:47:58 +00:00
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 ;
}
2021-02-25 08:57:58 +00:00
else if ( ! ParseSwizzleMask ( pValue , permuteElements , zeroElements , oneElements ) )
2021-01-10 00:47:58 +00:00
{
2021-02-25 08:57:58 +00:00
wprintf ( L " -swizzle requires a 1 to 4 character mask composed of these letters: r, g, b, a, x, y, w, z, 0, 1. \n Lowercase letters are from the first image, upper-case letters are from the second image. \n " ) ;
2021-01-10 00:47:58 +00:00
return 1 ;
}
break ;
2021-03-04 08:21:44 +00:00
case OPT_STRIP_MIPS :
switch ( dwCommand )
{
case CMD_CUBE :
case CMD_VOLUME :
case CMD_ARRAY :
case CMD_CUBEARRAY :
2021-03-11 04:42:37 +00:00
case CMD_MERGE :
2021-03-04 08:21:44 +00:00
break ;
default :
2021-03-11 04:42:37 +00:00
wprintf ( L " -stripmips only applies to cube, volume, array, cubearray, or merge commands \n " ) ;
2021-03-04 08:21:44 +00:00
return 1 ;
}
break ;
2019-07-06 06:48:39 +00:00
default :
break ;
2016-08-22 18:26:36 +00:00
}
}
2016-09-13 04:54:08 +00:00
else if ( wcspbrk ( pArg , L " ?* " ) ! = nullptr )
{
2022-03-01 22:31:55 +00:00
const size_t count = conversion . size ( ) ;
2016-09-13 04:54:08 +00:00
SearchForFiles ( pArg , conversion , ( dwOptions & ( 1 < < OPT_RECURSIVE ) ) ! = 0 ) ;
if ( conversion . size ( ) < = count )
{
wprintf ( L " No matching files found for %ls \n " , pArg ) ;
return 1 ;
}
}
2016-08-22 18:26:36 +00:00
else
2016-09-12 23:39:26 +00:00
{
2021-01-09 20:44:59 +00:00
SConversion conv = { } ;
2016-08-22 18:26:36 +00:00
wcscpy_s ( conv . szSrc , MAX_PATH , pArg ) ;
conversion . push_back ( conv ) ;
}
}
2016-09-12 23:39:26 +00:00
if ( conversion . empty ( ) )
2016-08-22 18:26:36 +00:00
{
PrintUsage ( ) ;
return 0 ;
}
2016-09-24 08:06:54 +00:00
if ( ~ dwOptions & ( 1 < < OPT_NOLOGO ) )
PrintLogo ( ) ;
switch ( dwCommand )
2016-08-22 18:26:36 +00:00
{
2016-09-24 08:06:54 +00:00
case CMD_H_CROSS :
case CMD_V_CROSS :
case CMD_H_STRIP :
case CMD_V_STRIP :
2018-02-09 22:32:57 +00:00
case CMD_GIF :
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2016-09-24 08:06:54 +00:00
if ( conversion . size ( ) > 1 )
{
2018-02-09 22:32:57 +00:00
wprintf ( L " ERROR: cross/strip/gif output only accepts 1 input file \n " ) ;
2016-09-24 08:06:54 +00:00
return 1 ;
}
2016-08-22 18:26:36 +00:00
break ;
2018-02-08 02:14:42 +00:00
case CMD_MERGE :
if ( conversion . size ( ) > 2 )
{
wprintf ( L " ERROR: merge output only accepts 2 input files \n " ) ;
return 1 ;
}
break ;
2019-07-06 06:48:39 +00:00
default :
break ;
2016-08-22 18:26:36 +00:00
}
// Convert images
size_t images = 0 ;
2016-09-12 23:39:26 +00:00
std : : vector < std : : unique_ptr < ScratchImage > > loadedImages ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
if ( dwCommand = = CMD_GIF )
2016-08-22 18:26:36 +00:00
{
2020-07-10 22:39:55 +00:00
wchar_t ext [ _MAX_EXT ] = { } ;
wchar_t fname [ _MAX_FNAME ] = { } ;
2018-02-09 22:32:57 +00:00
_wsplitpath_s ( conversion . front ( ) . szSrc , nullptr , 0 , nullptr , 0 , fname , _MAX_FNAME , ext , _MAX_EXT ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
wprintf ( L " reading %ls " , conversion . front ( ) . szSrc ) ;
fflush ( stdout ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
if ( ! * szOutputFile )
{
_wmakepath_s ( szOutputFile , nullptr , nullptr , fname , L " .dds " ) ;
2016-08-22 18:26:36 +00:00
}
2018-02-09 22:32:57 +00:00
hr = LoadAnimatedGif ( conversion . front ( ) . szSrc , loadedImages , ( dwOptions & ( 1 < < OPT_GIF_BGCOLOR ) ) ! = 0 ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
2018-02-09 22:32:57 +00:00
}
else
{
for ( auto pConv = conversion . begin ( ) ; pConv ! = conversion . end ( ) ; + + pConv )
2016-08-22 18:26:36 +00:00
{
2020-07-10 22:39:55 +00:00
wchar_t ext [ _MAX_EXT ] = { } ;
wchar_t fname [ _MAX_FNAME ] = { } ;
2018-02-09 22:32:57 +00:00
_wsplitpath_s ( pConv - > szSrc , nullptr , 0 , nullptr , 0 , fname , _MAX_FNAME , ext , _MAX_EXT ) ;
// Load source image
if ( pConv ! = conversion . begin ( ) )
wprintf ( L " \n " ) ;
else if ( ! * szOutputFile )
2016-08-22 18:26:36 +00:00
{
2018-02-09 22:32:57 +00:00
switch ( dwCommand )
2016-09-24 08:06:54 +00:00
{
2018-02-09 22:32:57 +00:00
case CMD_H_CROSS :
case CMD_V_CROSS :
case CMD_H_STRIP :
case CMD_V_STRIP :
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2018-02-09 22:32:57 +00:00
_wmakepath_s ( szOutputFile , nullptr , nullptr , fname , L " .bmp " ) ;
break ;
2016-09-24 08:06:54 +00:00
2018-02-09 22:32:57 +00:00
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 ;
2016-09-24 08:06:54 +00:00
}
}
2018-02-09 22:32:57 +00:00
wprintf ( L " reading %ls " , pConv - > szSrc ) ;
fflush ( stdout ) ;
TexMetadata info ;
std : : unique_ptr < ScratchImage > image ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! image )
2016-09-24 08:06:54 +00:00
{
2018-02-09 22:32:57 +00:00
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
2018-02-09 22:32:57 +00:00
switch ( dwCommand )
2016-08-22 18:26:36 +00:00
{
2018-02-09 22:32:57 +00:00
case CMD_H_CROSS :
case CMD_V_CROSS :
case CMD_H_STRIP :
case CMD_V_STRIP :
if ( _wcsicmp ( ext , L " .dds " ) = = 0 )
{
2020-07-09 21:13:38 +00:00
hr = LoadFromDDSFile ( pConv - > szSrc , DDS_FLAGS_ALLOW_LARGE_FILES , & info , * image ) ;
2018-02-09 22:32:57 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
if ( ! info . IsCubemap ( ) )
{
wprintf ( L " \n ERROR: Input must be a cubemap \n " ) ;
return 1 ;
}
else if ( info . arraySize ! = 6 )
{
wprintf ( L " \n WARNING: Only the first cubemap in an array is written out as a cross/strip \n " ) ;
}
}
else
2016-09-24 08:06:54 +00:00
{
2018-02-09 22:32:57 +00:00
wprintf ( L " \n ERROR: Input must be a dds of a cubemap \n " ) ;
2016-09-24 08:06:54 +00:00
return 1 ;
}
2018-02-09 22:32:57 +00:00
break ;
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2019-01-29 00:09:14 +00:00
if ( _wcsicmp ( ext , L " .dds " ) = = 0 )
{
2020-07-09 21:13:38 +00:00
hr = LoadFromDDSFile ( pConv - > szSrc , DDS_FLAGS_ALLOW_LARGE_FILES , & info , * image ) ;
2019-01-29 00:09:14 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2019-01-29 00:09:14 +00:00
return 1 ;
}
2016-09-24 08:06:54 +00:00
2019-01-29 00:26:46 +00:00
if ( info . dimension = = TEX_DIMENSION_TEXTURE3D | | info . arraySize < 2 | | info . IsCubemap ( ) )
2019-01-29 00:09:14 +00:00
{
2019-01-29 00:26:46 +00:00
wprintf ( L " \n ERROR: Input must be a 1D/2D array \n " ) ;
2019-01-29 00:09:14 +00:00
return 1 ;
}
}
else
{
2019-01-29 00:26:46 +00:00
wprintf ( L " \n ERROR: Input must be a dds of a 1D/2D array \n " ) ;
2019-01-29 00:09:14 +00:00
return 1 ;
}
break ;
2019-01-29 00:26:46 +00:00
2018-02-09 22:32:57 +00:00
default :
if ( _wcsicmp ( ext , L " .dds " ) = = 0 )
2016-09-24 08:06:54 +00:00
{
2020-07-09 21:13:38 +00:00
hr = LoadFromDDSFile ( pConv - > szSrc , DDS_FLAGS_ALLOW_LARGE_FILES , & info , * image ) ;
2018-02-09 22:32:57 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2021-03-04 08:21:44 +00:00
if ( info . IsVolumemap ( ) | | info . IsCubemap ( ) )
2018-02-09 22:32:57 +00:00
{
wprintf ( L " \n ERROR: Can't assemble complex surfaces \n " ) ;
return 1 ;
}
2021-03-04 08:21:44 +00:00
else if ( ( info . mipLevels > 1 ) & & ( ( dwOptions & ( 1 < < OPT_STRIP_MIPS ) ) = = 0 ) )
{
wprintf ( L " \n ERROR: Can't assemble using input mips. To ignore mips, try again with -stripmips \n " ) ;
return 1 ;
}
2016-09-24 08:06:54 +00:00
}
2018-02-09 22:32:57 +00:00
else if ( _wcsicmp ( ext , L " .tga " ) = = 0 )
2016-09-24 08:06:54 +00:00
{
2020-09-30 19:37:49 +00:00
hr = LoadFromTGAFile ( pConv - > szSrc , TGA_FLAGS_NONE , & info , * image ) ;
2018-02-09 22:32:57 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2016-09-24 08:06:54 +00:00
}
2018-02-09 22:32:57 +00:00
else if ( _wcsicmp ( ext , L " .hdr " ) = = 0 )
2016-09-24 08:06:54 +00:00
{
2018-02-09 22:32:57 +00:00
hr = LoadFromHDRFile ( pConv - > szSrc , & info , * image ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2016-09-24 08:06:54 +00:00
}
2018-02-09 22:32:57 +00:00
# ifdef USE_OPENEXR
else if ( _wcsicmp ( ext , L " .exr " ) = = 0 )
2016-10-02 19:44:07 +00:00
{
2018-02-09 22:32:57 +00:00
hr = LoadFromEXRFile ( pConv - > szSrc , & info , * image ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-02-04 00:04:36 +00:00
return 1 ;
2018-02-09 22:32:57 +00:00
}
2016-10-02 19:44:07 +00:00
}
2018-02-09 22:32:57 +00:00
# endif
else
2016-09-24 08:06:54 +00:00
{
2018-02-09 22:32:57 +00:00
// WIC shares the same filter values for mode and dither
2019-07-06 06:48:39 +00:00
static_assert ( static_cast < int > ( WIC_FLAGS_DITHER ) = = static_cast < int > ( TEX_FILTER_DITHER ) , " WIC_FLAGS_* & TEX_FILTER_* should match " ) ;
static_assert ( static_cast < int > ( WIC_FLAGS_DITHER_DIFFUSION ) = = static_cast < int > ( TEX_FILTER_DITHER_DIFFUSION ) , " WIC_FLAGS_* & TEX_FILTER_* should match " ) ;
static_assert ( static_cast < int > ( WIC_FLAGS_FILTER_POINT ) = = static_cast < int > ( TEX_FILTER_POINT ) , " WIC_FLAGS_* & TEX_FILTER_* should match " ) ;
static_assert ( static_cast < int > ( WIC_FLAGS_FILTER_LINEAR ) = = static_cast < int > ( TEX_FILTER_LINEAR ) , " WIC_FLAGS_* & TEX_FILTER_* should match " ) ;
static_assert ( static_cast < int > ( WIC_FLAGS_FILTER_CUBIC ) = = static_cast < int > ( TEX_FILTER_CUBIC ) , " WIC_FLAGS_* & TEX_FILTER_* should match " ) ;
static_assert ( static_cast < int > ( WIC_FLAGS_FILTER_FANT ) = = static_cast < int > ( TEX_FILTER_FANT ) , " WIC_FLAGS_* & TEX_FILTER_* should match " ) ;
2018-02-09 22:32:57 +00:00
2020-07-10 22:39:55 +00:00
hr = LoadFromWICFile ( pConv - > szSrc , WIC_FLAGS_ALL_FRAMES | dwFilter , & info , * image ) ;
2018-02-09 22:32:57 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2022-03-02 22:25:27 +00:00
if ( hr = = static_cast < HRESULT > ( 0xc00d5212 ) /* MF_E_TOPO_CODEC_NOT_FOUND */ )
{
if ( _wcsicmp ( ext , L " .heic " ) = = 0 | | _wcsicmp ( ext , L " .heif " ) = = 0 )
{
wprintf ( L " INFO: This format requires installing the HEIF Image Extensions - https://aka.ms/heif \n " ) ;
}
else if ( _wcsicmp ( ext , L " .webp " ) = = 0 )
{
wprintf ( L " INFO: This format requires installing the WEBP Image Extensions - https://www.microsoft.com/p/webp-image-extensions/9pg2dk419drg \n " ) ;
}
}
2018-02-09 22:32:57 +00:00
return 1 ;
}
2016-09-24 08:06:54 +00:00
}
2018-02-09 22:32:57 +00:00
break ;
2016-09-24 08:06:54 +00:00
}
2018-02-09 22:32:57 +00:00
PrintInfo ( info ) ;
2016-09-24 08:06:54 +00:00
2018-02-09 22:32:57 +00:00
// Convert texture
fflush ( stdout ) ;
2016-09-24 08:06:54 +00:00
2018-02-09 22:32:57 +00:00
// --- Planar ------------------------------------------------------------------
if ( IsPlanar ( info . format ) )
2016-09-11 03:43:33 +00:00
{
2018-02-09 22:32:57 +00:00
auto img = image - > GetImage ( 0 , 0 , 0 ) ;
assert ( img ) ;
2022-03-01 22:31:55 +00:00
const size_t nimg = image - > GetImageCount ( ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
2016-09-24 08:06:54 +00:00
2018-02-09 22:32:57 +00:00
hr = ConvertToSinglePlane ( img , nimg , info , * timage ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [converttosingleplane] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-02-04 00:04:36 +00:00
return 1 ;
2018-02-09 22:32:57 +00:00
}
2016-09-24 08:06:54 +00:00
2018-02-09 22:32:57 +00:00
auto & tinfo = timage - > GetMetadata ( ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
info . format = tinfo . format ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
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 ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
image . swap ( timage ) ;
2016-08-22 18:26:36 +00:00
}
2018-02-09 22:32:57 +00:00
// --- Decompress --------------------------------------------------------------
if ( IsCompressed ( info . format ) )
2016-09-24 08:06:54 +00:00
{
2018-02-09 22:32:57 +00:00
const Image * img = image - > GetImage ( 0 , 0 , 0 ) ;
2016-09-24 08:06:54 +00:00
assert ( img ) ;
2022-03-01 22:31:55 +00:00
const size_t nimg = image - > GetImageCount ( ) ;
2016-09-24 08:06:54 +00:00
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
2018-02-09 22:32:57 +00:00
hr = Decompress ( img , nimg , info , DXGI_FORMAT_UNKNOWN /* picks good default */ , * timage . get ( ) ) ;
2016-09-24 08:06:54 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [decompress] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-02-04 00:04:36 +00:00
return 1 ;
2016-09-24 08:06:54 +00:00
}
2019-07-06 06:48:39 +00:00
auto & tinfo = timage - > GetMetadata ( ) ;
2018-02-09 22:32:57 +00:00
info . format = tinfo . format ;
2016-09-24 08:06:54 +00:00
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 ) ;
}
2021-03-04 08:21:44 +00:00
// --- Strip Mips (if requested) -----------------------------------------------
if ( ( info . mipLevels > 1 ) & & ( dwOptions & ( 1 < < OPT_STRIP_MIPS ) ) )
{
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
TexMetadata mdata = info ;
mdata . mipLevels = 1 ;
hr = timage - > Initialize ( mdata ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [copy to single level] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-03-04 08:21:44 +00:00
return 1 ;
}
if ( info . dimension = = TEX_DIMENSION_TEXTURE3D )
{
for ( size_t d = 0 ; d < info . depth ; + + d )
{
hr = CopyRectangle ( * image - > GetImage ( 0 , 0 , d ) , Rect ( 0 , 0 , info . width , info . height ) ,
* timage - > GetImage ( 0 , 0 , d ) , TEX_FILTER_DEFAULT , 0 , 0 ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [copy to single level] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-03-04 08:21:44 +00:00
return 1 ;
}
}
}
else
{
for ( size_t i = 0 ; i < info . arraySize ; + + i )
{
hr = CopyRectangle ( * image - > GetImage ( 0 , i , 0 ) , Rect ( 0 , 0 , info . width , info . height ) ,
* timage - > GetImage ( 0 , i , 0 ) , TEX_FILTER_DEFAULT , 0 , 0 ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [copy to single level] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-03-04 08:21:44 +00:00
return 1 ;
}
}
}
image . swap ( timage ) ;
info . mipLevels = 1 ;
}
2018-02-09 22:32:57 +00:00
// --- Undo Premultiplied Alpha (if requested) ---------------------------------
if ( ( dwOptions & ( 1 < < OPT_DEMUL_ALPHA ) )
& & HasAlpha ( info . format )
& & info . format ! = DXGI_FORMAT_A8_UNORM )
2016-08-22 18:26:36 +00:00
{
2018-02-09 22:32:57 +00:00
if ( info . GetAlphaMode ( ) = = TEX_ALPHA_MODE_STRAIGHT )
{
printf ( " \n WARNING: Image is already using straight alpha \n " ) ;
}
else if ( ! info . IsPMAlpha ( ) )
{
printf ( " \n WARNING: Image is not using premultipled alpha \n " ) ;
}
else
{
auto img = image - > GetImage ( 0 , 0 , 0 ) ;
assert ( img ) ;
2022-03-01 22:31:55 +00:00
const size_t nimg = image - > GetImageCount ( ) ;
2018-02-09 22:32:57 +00:00
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
hr = PremultiplyAlpha ( img , nimg , info , TEX_PMALPHA_REVERSE | dwSRGB , * timage ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [demultiply alpha] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2021-02-04 00:04:36 +00:00
return 1 ;
2018-02-09 22:32:57 +00:00
}
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 ) ;
}
2016-08-22 18:26:36 +00:00
}
2018-02-09 22:32:57 +00:00
// --- Resize ------------------------------------------------------------------
if ( ! width )
2016-08-22 18:26:36 +00:00
{
2018-02-09 22:32:57 +00:00
width = info . width ;
2016-08-22 18:26:36 +00:00
}
2018-02-09 22:32:57 +00:00
if ( ! height )
{
height = info . height ;
}
if ( info . width ! = width | | info . height ! = height )
{
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
hr = Resize ( image - > GetImages ( ) , image - > GetImageCount ( ) , image - > GetMetadata ( ) , width , height , dwFilter | dwFilterOpts , * timage . get ( ) ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [resize] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2016-08-22 18:26:36 +00:00
2019-07-06 06:48:39 +00:00
auto & tinfo = timage - > GetMetadata ( ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
assert ( tinfo . width = = width & & tinfo . height = = height & & tinfo . mipLevels = = 1 ) ;
info . width = tinfo . width ;
info . height = tinfo . height ;
info . mipLevels = 1 ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
assert ( info . depth = = tinfo . depth ) ;
assert ( info . arraySize = = tinfo . arraySize ) ;
assert ( info . miscFlags = = tinfo . miscFlags ) ;
assert ( info . format = = tinfo . format ) ;
assert ( info . dimension = = tinfo . dimension ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
image . swap ( timage ) ;
2017-02-26 07:57:13 +00:00
}
2018-02-09 22:32:57 +00:00
// --- Tonemap (if requested) --------------------------------------------------
if ( dwOptions & ( 1 < < OPT_TONEMAP ) )
2017-02-26 07:57:13 +00:00
{
2018-02-09 22:32:57 +00:00
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
2017-02-26 07:57:13 +00:00
2018-02-09 22:32:57 +00:00
// Compute max luminosity across all images
XMVECTOR maxLum = XMVectorZero ( ) ;
hr = EvaluateImage ( image - > GetImages ( ) , image - > GetImageCount ( ) , image - > GetMetadata ( ) ,
2019-07-06 06:48:39 +00:00
[ & ] ( const XMVECTOR * pixels , size_t w , size_t y )
2018-02-09 22:32:57 +00:00
{
2019-09-14 00:31:09 +00:00
UNREFERENCED_PARAMETER ( y ) ;
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
for ( size_t j = 0 ; j < w ; + + j )
{
static const XMVECTORF32 s_luminance = { { { 0.3f , 0.59f , 0.11f , 0.f } } } ;
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
XMVECTOR v = * pixels + + ;
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
v = XMVector3Dot ( v , s_luminance ) ;
maxLum = XMVectorMax ( v , maxLum ) ;
}
} ) ;
2018-02-09 22:32:57 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [tonemap maxlum] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
// Reinhard et al, "Photographic Tone Reproduction for Digital Images"
2018-02-09 22:32:57 +00:00
// http://www.cs.utah.edu/~reinhard/cdrom/
maxLum = XMVectorMultiply ( maxLum , maxLum ) ;
2017-02-26 07:57:13 +00:00
2018-02-09 22:32:57 +00:00
hr = TransformImage ( image - > GetImages ( ) , image - > GetImageCount ( ) , image - > GetMetadata ( ) ,
2019-07-06 06:48:39 +00:00
[ & ] ( XMVECTOR * outPixels , const XMVECTOR * inPixels , size_t w , size_t y )
2018-02-09 22:32:57 +00:00
{
2019-09-14 00:31:09 +00:00
UNREFERENCED_PARAMETER ( y ) ;
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
for ( size_t j = 0 ; j < w ; + + j )
{
XMVECTOR value = inPixels [ j ] ;
2017-02-26 07:57:13 +00:00
2022-03-01 22:31:55 +00:00
const XMVECTOR scale = XMVectorDivide (
2019-09-14 00:31:09 +00:00
XMVectorAdd ( g_XMOne , XMVectorDivide ( value , maxLum ) ) ,
XMVectorAdd ( g_XMOne , value ) ) ;
2022-03-01 22:31:55 +00:00
const XMVECTOR nvalue = XMVectorMultiply ( value , scale ) ;
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
value = XMVectorSelect ( value , nvalue , g_XMSelect1110 ) ;
outPixels [ j ] = value ;
}
} , * timage ) ;
2018-02-09 22:32:57 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [tonemap apply] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2017-02-26 07:57:13 +00:00
2019-09-14 00:31:09 +00:00
# ifndef NDEBUG
2018-02-09 22:32:57 +00:00
auto & tinfo = timage - > GetMetadata ( ) ;
2019-09-14 00:31:09 +00:00
# endif
2017-02-26 07:57:13 +00:00
2018-02-09 22:32:57 +00:00
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 ) ;
2017-02-26 07:57:13 +00:00
2018-02-09 22:32:57 +00:00
image . swap ( timage ) ;
2016-08-22 18:26:36 +00:00
}
2018-02-09 22:32:57 +00:00
// --- Convert -----------------------------------------------------------------
if ( format = = DXGI_FORMAT_UNKNOWN )
2016-08-22 18:26:36 +00:00
{
2018-02-09 22:32:57 +00:00
format = info . format ;
2016-08-22 18:26:36 +00:00
}
2018-02-09 22:32:57 +00:00
else if ( info . format ! = format & & ! IsCompressed ( format ) )
{
std : : unique_ptr < ScratchImage > timage ( new ( std : : nothrow ) ScratchImage ) ;
if ( ! timage )
{
wprintf ( L " \n ERROR: Memory allocation failed \n " ) ;
return 1 ;
}
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
hr = Convert ( image - > GetImages ( ) , image - > GetImageCount ( ) , image - > GetMetadata ( ) , format ,
dwFilter | dwFilterOpts | dwSRGB , TEX_THRESHOLD_DEFAULT , * timage . get ( ) ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [convert] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-09 22:32:57 +00:00
return 1 ;
}
2016-08-22 18:26:36 +00:00
2019-07-06 06:48:39 +00:00
auto & tinfo = timage - > GetMetadata ( ) ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
assert ( tinfo . format = = format ) ;
info . format = tinfo . format ;
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
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 ) ;
}
2016-08-22 18:26:36 +00:00
2018-02-09 22:32:57 +00:00
images + = info . arraySize ;
loadedImages . emplace_back ( std : : move ( image ) ) ;
}
2016-08-22 18:26:36 +00:00
}
2016-09-24 08:06:54 +00:00
switch ( dwCommand )
2016-08-22 18:26:36 +00:00
{
2016-09-24 08:06:54 +00:00
case CMD_CUBE :
2016-09-12 23:39:26 +00:00
if ( images ! = 6 )
2016-08-22 18:26:36 +00:00
{
2016-09-24 08:06:54 +00:00
wprintf ( L " \n ERROR: cube requires six images to form the faces of the cubemap \n " ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
break ;
2016-09-24 08:06:54 +00:00
case CMD_CUBEARRAY :
2016-09-12 23:39:26 +00:00
if ( ( images < 6 ) | | ( images % 6 ) ! = 0 )
2016-08-22 18:26:36 +00:00
{
2016-09-24 08:06:54 +00:00
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 :
2018-02-09 22:32:57 +00:00
case CMD_GIF :
2016-09-24 08:06:54 +00:00
break ;
default :
if ( images < 2 )
{
wprintf ( L " \n ERROR: Need at least 2 images to assemble \n \n " ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
break ;
}
// --- Create result ---------------------------------------------------------------
2016-09-24 08:06:54 +00:00
switch ( dwCommand )
{
case CMD_H_CROSS :
case CMD_V_CROSS :
case CMD_H_STRIP :
case CMD_V_STRIP :
{
2016-09-25 20:38:04 +00:00
size_t twidth = 0 ;
size_t theight = 0 ;
2016-09-24 08:06:54 +00:00
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 ;
2019-07-06 06:48:39 +00:00
break ;
default :
break ;
2016-09-24 08:06:54 +00:00
}
ScratchImage result ;
hr = result . Initialize2D ( format , twidth , theight , 1 , 1 ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED setting up result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-09-24 08:06:54 +00:00
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 ;
}
2022-03-01 22:31:55 +00:00
const Rect rect ( 0 , 0 , width , height ) ;
2016-09-24 08:06:54 +00:00
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 ;
2019-07-06 06:48:39 +00:00
default :
break ;
2016-09-24 08:06:54 +00:00
}
hr = CopyRectangle ( * img , rect , * dest , dwFilter | dwFilterOpts , offsetx , offsety ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED building result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-09-24 08:06:54 +00:00
return 1 ;
}
}
// Write cross/strip
wprintf ( L " \n Writing %ls " , szOutputFile ) ;
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
2020-04-14 00:22:55 +00:00
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2021-10-17 18:57:07 +00:00
std : : ignore = _wcslwr_s ( szOutputFile ) ;
2020-04-14 00:22:55 +00:00
}
2016-09-25 20:38:04 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
2016-09-24 08:06:54 +00:00
{
if ( GetFileAttributesW ( szOutputFile ) ! = INVALID_FILE_ATTRIBUTES )
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
2018-02-08 02:14:42 +00:00
hr = SaveImageFile ( * dest , fileType , szOutputFile ) ;
if ( FAILED ( hr ) )
2016-09-24 08:06:54 +00:00
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-08 02:14:42 +00:00
return 1 ;
}
break ;
}
2016-09-24 08:06:54 +00:00
2018-02-08 02:14:42 +00:00
case CMD_MERGE :
{
2021-01-10 00:47:58 +00:00
// 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 ) ;
2018-02-08 02:14:42 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [convert second input] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-08 02:14:42 +00:00
return 1 ;
}
2016-09-24 08:06:54 +00:00
2021-01-10 00:47:58 +00:00
const Image & img = * tempImage . GetImage ( 0 , 0 , 0 ) ;
2016-09-24 08:06:54 +00:00
2021-01-10 00:47:58 +00:00
// Merge with our first source image
2018-02-08 02:14:42 +00:00
const Image & rgb = * loadedImages [ 0 ] - > GetImage ( 0 , 0 , 0 ) ;
2022-03-01 22:31:55 +00:00
const XMVECTOR zc = XMVectorSelectControl ( zeroElements [ 0 ] , zeroElements [ 1 ] , zeroElements [ 2 ] , zeroElements [ 3 ] ) ;
const XMVECTOR oc = XMVectorSelectControl ( oneElements [ 0 ] , oneElements [ 1 ] , oneElements [ 2 ] , oneElements [ 3 ] ) ;
2021-02-25 08:57:58 +00:00
2018-02-08 02:14:42 +00:00
ScratchImage result ;
2021-02-25 08:57:58 +00:00
hr = TransformImage ( rgb , [ & , zc , oc ] ( XMVECTOR * outPixels , const XMVECTOR * inPixels , size_t w , size_t y )
2018-02-08 02:14:42 +00:00
{
2021-01-10 00:47:58 +00:00
const XMVECTOR * inPixels2 = reinterpret_cast < XMVECTOR * > ( img . pixels + img . rowPitch * y ) ;
2019-09-14 00:31:09 +00:00
for ( size_t j = 0 ; j < w ; + + j )
{
2021-06-16 07:02:58 +00:00
XMVECTOR pixel = XMVectorPermute ( inPixels [ j ] , inPixels2 [ j ] ,
2021-01-10 00:47:58 +00:00
permuteElements [ 0 ] , permuteElements [ 1 ] , permuteElements [ 2 ] , permuteElements [ 3 ] ) ;
2021-06-16 07:02:58 +00:00
pixel = XMVectorSelect ( pixel , g_XMZero , zc ) ;
outPixels [ j ] = XMVectorSelect ( pixel , g_XMOne , oc ) ;
2019-09-14 00:31:09 +00:00
}
} , result ) ;
2018-02-08 02:14:42 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED [merge image] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2018-02-08 02:14:42 +00:00
return 1 ;
}
// Write merged texture
wprintf ( L " \n Writing %ls " , szOutputFile ) ;
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
2020-04-14 00:22:55 +00:00
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2021-10-17 18:57:07 +00:00
std : : ignore = _wcslwr_s ( szOutputFile ) ;
2020-04-14 00:22:55 +00:00
}
2018-02-08 02:14:42 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
if ( GetFileAttributesW ( szOutputFile ) ! = INVALID_FILE_ATTRIBUTES )
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
2016-09-24 08:06:54 +00:00
}
2018-02-08 02:14:42 +00:00
hr = SaveImageFile ( * result . GetImage ( 0 , 0 , 0 ) , fileType , szOutputFile ) ;
2016-09-24 08:06:54 +00:00
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-09-24 08:06:54 +00:00
return 1 ;
}
break ;
}
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2019-01-29 00:09:14 +00:00
{
2022-03-01 22:31:55 +00:00
const size_t twidth = width ;
const size_t theight = height * images ;
2019-01-29 00:09:14 +00:00
ScratchImage result ;
hr = result . Initialize2D ( format , twidth , theight , 1 , 1 ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED setting up result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2019-01-29 00:09:14 +00:00
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 ;
}
2022-03-01 22:31:55 +00:00
const Rect rect ( 0 , 0 , width , height ) ;
2019-01-29 00:09:14 +00:00
2022-03-01 22:31:55 +00:00
constexpr size_t offsetx = 0 ;
2019-01-29 00:09:14 +00:00
size_t offsety = 0 ;
offsety = index * height ;
hr = CopyRectangle ( * img , rect , * dest , dwFilter | dwFilterOpts , offsetx , offsety ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED building result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2019-01-29 00:09:14 +00:00
return 1 ;
}
}
2019-01-29 00:26:46 +00:00
// Write array strip
2019-01-29 00:09:14 +00:00
wprintf ( L " \n Writing %ls " , szOutputFile ) ;
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
2020-04-14 00:22:55 +00:00
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2021-10-17 18:57:07 +00:00
std : : ignore = _wcslwr_s ( szOutputFile ) ;
2020-04-14 00:22:55 +00:00
}
2019-01-29 00:09:14 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
if ( GetFileAttributesW ( szOutputFile ) ! = INVALID_FILE_ATTRIBUTES )
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
hr = SaveImageFile ( * dest , fileType , szOutputFile ) ;
if ( FAILED ( hr ) )
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2019-01-29 00:09:14 +00:00
return 1 ;
}
break ;
}
2016-09-24 08:06:54 +00:00
default :
2016-08-22 18:26:36 +00:00
{
std : : vector < Image > imageArray ;
2016-09-12 23:39:26 +00:00
imageArray . reserve ( images ) ;
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
for ( auto it = loadedImages . cbegin ( ) ; it ! = loadedImages . cend ( ) ; + + it )
2016-08-22 18:26:36 +00:00
{
const ScratchImage * simage = it - > get ( ) ;
2019-07-06 06:48:39 +00:00
assert ( simage ! = nullptr ) ;
2016-09-12 23:39:26 +00:00
for ( size_t j = 0 ; j < simage - > GetMetadata ( ) . arraySize ; + + j )
2016-08-22 18:26:36 +00:00
{
2016-09-12 23:39:26 +00:00
const Image * img = simage - > GetImage ( 0 , j , 0 ) ;
2019-07-06 06:48:39 +00:00
assert ( img ! = nullptr ) ;
2016-09-12 23:39:26 +00:00
imageArray . push_back ( * img ) ;
2016-08-22 18:26:36 +00:00
}
}
2020-07-09 20:59:11 +00:00
switch ( dwCommand )
{
case CMD_CUBE :
if ( imageArray [ 0 ] . width > maxCube | | imageArray [ 0 ] . height > maxCube )
{
2021-06-04 22:06:31 +00:00
wprintf ( L " \n WARNING: Target size exceeds maximum cube dimensions for feature level (%u) \n " , maxCube ) ;
2020-07-09 20:59:11 +00:00
}
break ;
case CMD_VOLUME :
if ( imageArray [ 0 ] . width > maxVolume | | imageArray [ 0 ] . height > maxVolume | | imageArray . size ( ) > maxVolume )
{
2021-06-04 22:06:31 +00:00
wprintf ( L " \n WARNING: Target size exceeds volume extent for feature level (%u) \n " , maxVolume ) ;
2020-07-09 20:59:11 +00:00
}
break ;
case CMD_ARRAY :
if ( imageArray [ 0 ] . width > maxSize | | imageArray [ 0 ] . height > maxSize | | imageArray . size ( ) > maxArray )
{
2021-06-04 22:06:31 +00:00
wprintf ( L " \n WARNING: Target size exceeds maximum size for feature level (size %u, array %u) \n " , maxSize , maxArray ) ;
2020-07-09 20:59:11 +00:00
}
break ;
case CMD_CUBEARRAY :
if ( imageArray [ 0 ] . width > maxCube | | imageArray [ 0 ] . height > maxCube | | imageArray . size ( ) > maxArray )
{
2021-06-04 22:06:31 +00:00
wprintf ( L " \n WARNING: Target size exceeds maximum cube dimensions for feature level (size %u, array %u) \n " , maxCube , maxArray ) ;
2020-07-09 20:59:11 +00:00
}
break ;
default :
if ( imageArray [ 0 ] . width > maxSize | | imageArray [ 0 ] . height > maxSize )
{
2021-06-04 22:06:31 +00:00
wprintf ( L " \n WARNING: Target size exceeds maximum size for feature level (%u) \n " , maxSize ) ;
2020-07-09 20:59:11 +00:00
}
break ;
}
2016-08-22 18:26:36 +00:00
ScratchImage result ;
2016-09-24 08:06:54 +00:00
switch ( dwCommand )
2016-08-22 18:26:36 +00:00
{
2016-09-24 08:06:54 +00:00
case CMD_VOLUME :
2016-09-12 23:39:26 +00:00
hr = result . Initialize3DFromImages ( & imageArray [ 0 ] , imageArray . size ( ) ) ;
2016-08-22 18:26:36 +00:00
break ;
2016-09-24 08:06:54 +00:00
case CMD_ARRAY :
2018-02-09 22:32:57 +00:00
case CMD_GIF :
2016-09-12 23:39:26 +00:00
hr = result . InitializeArrayFromImages ( & imageArray [ 0 ] , imageArray . size ( ) , ( dwOptions & ( 1 < < OPT_USE_DX10 ) ) ! = 0 ) ;
2016-08-22 18:26:36 +00:00
break ;
2016-09-24 08:06:54 +00:00
case CMD_CUBE :
case CMD_CUBEARRAY :
2016-09-12 23:39:26 +00:00
hr = result . InitializeCubeFromImages ( & imageArray [ 0 ] , imageArray . size ( ) ) ;
2016-08-22 18:26:36 +00:00
break ;
2019-07-06 06:48:39 +00:00
default :
break ;
2016-08-22 18:26:36 +00:00
}
2016-09-12 23:39:26 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2021-04-01 07:59:57 +00:00
wprintf ( L " FAILED building result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
// Write texture
2016-09-12 23:39:26 +00:00
wprintf ( L " \n Writing %ls " , szOutputFile ) ;
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
2016-08-22 18:26:36 +00:00
fflush ( stdout ) ;
2020-04-14 00:22:55 +00:00
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2021-10-17 18:57:07 +00:00
std : : ignore = _wcslwr_s ( szOutputFile ) ;
2020-04-14 00:22:55 +00:00
}
2016-09-25 20:38:04 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
2016-09-24 08:06:54 +00:00
{
if ( GetFileAttributesW ( szOutputFile ) ! = INVALID_FILE_ATTRIBUTES )
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
2016-09-12 23:39:26 +00:00
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 ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
2021-04-01 07:59:57 +00:00
wprintf ( L " \n FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2016-08-22 18:26:36 +00:00
return 1 ;
}
2016-09-24 08:06:54 +00:00
break ;
}
2016-08-22 18:26:36 +00:00
}
return 0 ;
}