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
//--------------------------------------------------------------------------------------
2023-12-30 20:45:09 +00:00
# ifdef _MSC_VER
2016-09-11 03:43:33 +00:00
# pragma warning(push)
# pragma warning(disable : 4005)
2023-12-30 20:45:09 +00:00
# endif
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
2023-12-30 20:45:09 +00:00
# ifdef _MSC_VER
2016-09-11 03:43:33 +00:00
# pragma warning(pop)
2023-12-30 20:45:09 +00:00
# endif
2016-08-22 18:26:36 +00:00
2023-03-27 23:02:41 +00:00
# if __cplusplus < 201703L
# error Requires C++17 (and / Zc:__cplusplus with MSVC)
# endif
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>
2022-05-01 07:44:49 +00:00
# include <cstring>
2021-01-07 08:43:18 +00:00
# include <cwchar>
2021-06-08 22:00:22 +00:00
# include <cwctype>
2023-03-27 23:02:41 +00:00
# include <filesystem>
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>
2023-12-30 20:45:09 +00:00
# ifdef _MSC_VER
2019-10-24 23:55:13 +00:00
# pragma warning(disable : 4619 4616 26812)
2023-12-30 20:45:09 +00:00
# endif
2019-10-24 23:55:13 +00:00
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
# ifdef USE_OPENEXR
// See <https://github.com/Microsoft/DirectXTex/wiki/Adding-OpenEXR> for details
# include "DirectXTexEXR.h"
# endif
2024-01-20 19:02:19 +00:00
// See <https://github.com/Microsoft/DirectXTex/wiki/Using-JPEG-PNG-OSS> for details
# ifdef USE_LIBJPEG
# include "DirectXTexJPEG.h"
# endif
# ifdef USE_LIBPNG
# include "DirectXTexPNG.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 ,
2022-11-05 00:42:27 +00:00
CMD_V_CROSS_FNZ ,
CMD_H_TEE ,
2020-07-01 08:37:13 +00:00
CMD_H_STRIP ,
CMD_V_STRIP ,
CMD_MERGE ,
CMD_GIF ,
CMD_ARRAY_STRIP ,
2022-11-20 18:47:30 +00:00
CMD_CUBE_FROM_HC ,
CMD_CUBE_FROM_VC ,
CMD_CUBE_FROM_VC_FNZ ,
CMD_CUBE_FROM_HT ,
CMD_CUBE_FROM_HS ,
CMD_CUBE_FROM_VS ,
2024-02-15 06:25:11 +00:00
CMD_FROM_MIPS ,
2020-07-01 08:37:13 +00:00
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
{
2023-06-13 22:40:45 +00:00
std : : wstring szSrc ;
2020-07-01 08:37:13 +00:00
} ;
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 [ ] =
{
2022-11-20 18:47:30 +00:00
{ 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 " v-cross-fnz " , CMD_V_CROSS_FNZ } ,
{ L " h-tee " , CMD_H_TEE } ,
{ 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 } ,
{ L " cube-from-hc " , CMD_CUBE_FROM_HC } ,
{ L " cube-from-vc " , CMD_CUBE_FROM_VC } ,
{ L " cube-from-vc-fnz " , CMD_CUBE_FROM_VC_FNZ } ,
{ L " cube-from-ht " , CMD_CUBE_FROM_HT } ,
{ L " cube-from-hs " , CMD_CUBE_FROM_HS } ,
{ L " cube-from-vs " , CMD_CUBE_FROM_VS } ,
2024-02-15 06:25:11 +00:00
{ L " from-mips " , CMD_FROM_MIPS } ,
2020-07-01 08:37:13 +00:00
{ 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 ) ,
2023-05-11 16:58:28 +00:00
// D3D11on12 format
{ L " A4B4G4R4_UNORM " , DXGI_FORMAT ( 191 ) } ,
2020-07-01 08:37:13 +00:00
{ 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
2024-01-20 19:02:19 +00:00
# endif
# ifdef USE_LIBJPEG
# define CODEC_JPEG 0xFFFF0007
# endif
# ifdef USE_LIBPNG
# define CODEC_PNG 0xFFFF0008
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 [ ] =
{
2024-01-20 19:02:19 +00:00
{ L " .BMP " , WIC_CODEC_BMP } ,
# ifdef USE_LIBJPEG
{ L " .JPG " , CODEC_JPEG } ,
{ L " .JPEG " , CODEC_JPEG } ,
# else
2020-07-01 08:37:13 +00:00
{ L " .JPG " , WIC_CODEC_JPEG } ,
{ L " .JPEG " , WIC_CODEC_JPEG } ,
2024-01-20 19:02:19 +00:00
# endif
# ifdef USE_LIBPNG
{ L " .PNG " , CODEC_PNG } ,
# else
{ L " .PNG " , WIC_CODEC_PNG } ,
# endif
{ L " .DDS " , CODEC_DDS } ,
{ L " .TGA " , CODEC_TGA } ,
{ L " .HDR " , CODEC_HDR } ,
2020-07-01 08:37:13 +00:00
{ L " .TIF " , WIC_CODEC_TIFF } ,
{ L " .TIFF " , WIC_CODEC_TIFF } ,
2024-01-20 19:02:19 +00:00
{ 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-01 08:37:13 +00:00
} ;
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
2023-06-13 22:40:45 +00:00
void SearchForFiles ( const std : : filesystem : : path & path , std : : list < SConversion > & files , bool recursive )
2016-09-13 04:54:08 +00:00
{
// Process files
2019-02-07 22:52:57 +00:00
WIN32_FIND_DATAW findData = { } ;
2023-06-13 22:40:45 +00:00
ScopedFindHandle hFile ( safe_handle ( FindFirstFileExW ( path . c_str ( ) ,
2016-09-13 04:54:08 +00:00
FindExInfoBasic , & findData ,
FindExSearchNameMatch , nullptr ,
FIND_FIRST_EX_LARGE_FETCH ) ) ) ;
if ( hFile )
{
for ( ; ; )
{
if ( ! ( findData . dwFileAttributes & ( FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY ) ) )
{
2021-01-09 20:44:59 +00:00
SConversion conv = { } ;
2023-06-13 22:40:45 +00:00
conv . szSrc = path . parent_path ( ) . append ( findData . cFileName ) . native ( ) ;
2016-09-13 04:54:08 +00:00
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 )
{
2023-06-13 22:40:45 +00:00
auto searchDir = path . parent_path ( ) . append ( L " * " ) ;
2016-09-13 04:54:08 +00:00
2023-06-13 22:40:45 +00:00
hFile . reset ( safe_handle ( FindFirstFileExW ( searchDir . c_str ( ) ,
2016-09-13 04:54:08 +00:00
FindExInfoBasic , & findData ,
FindExSearchLimitToDirectories , nullptr ,
FIND_FIRST_EX_LARGE_FETCH ) ) ) ;
if ( ! hFile )
return ;
for ( ; ; )
{
if ( findData . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
if ( findData . cFileName [ 0 ] ! = L ' . ' )
{
2023-06-13 22:40:45 +00:00
auto subdir = path . parent_path ( ) . append ( findData . cFileName ) . append ( path . filename ( ) . c_str ( ) ) ;
2016-09-13 04:54:08 +00:00
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 ;
2023-06-13 22:40:45 +00:00
2021-06-08 22:00:22 +00:00
for ( ; ; )
{
2023-10-06 21:18:53 +00:00
std : : wstring fname ;
std : : getline ( inFile , fname ) ;
2021-06-08 22:00:22 +00:00
if ( ! inFile )
break ;
2023-06-13 22:40:45 +00:00
if ( fname [ 0 ] = = L ' # ' )
2021-06-08 22:00:22 +00:00
{
// Comment
}
2023-06-13 22:40:45 +00:00
else if ( fname [ 0 ] = = L ' - ' )
2021-06-08 22:00:22 +00:00
{
if ( flist . empty ( ) )
{
2023-10-06 21:18:53 +00:00
wprintf ( L " WARNING: Ignoring the line '%ls' in -flist \n " , fname . c_str ( ) ) ;
2021-06-08 22:00:22 +00:00
}
else
{
2023-10-06 21:18:53 +00:00
std : : filesystem : : path path ( fname . c_str ( ) + 1 ) ;
2023-03-27 23:02:41 +00:00
auto & npath = path . make_preferred ( ) ;
2023-10-06 21:18:53 +00:00
if ( wcspbrk ( fname . c_str ( ) , L " ?* " ) ! = nullptr )
2021-06-08 22:00:22 +00:00
{
std : : list < SConversion > removeFiles ;
2023-06-13 22:40:45 +00:00
SearchForFiles ( npath , removeFiles , false ) ;
2021-06-08 22:00:22 +00:00
2023-03-27 23:02:41 +00:00
for ( auto & it : removeFiles )
2021-06-08 22:00:22 +00:00
{
2023-06-13 22:40:45 +00:00
std : : wstring name = it . szSrc ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , towlower ) ;
excludes . insert ( name ) ;
2021-06-08 22:00:22 +00:00
}
}
else
{
2023-03-27 23:02:41 +00:00
std : : wstring name = npath . c_str ( ) ;
2021-06-08 22:00:22 +00:00
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , towlower ) ;
excludes . insert ( name ) ;
}
}
}
2023-10-06 21:18:53 +00:00
else if ( wcspbrk ( fname . c_str ( ) , L " ?* " ) ! = nullptr )
2021-06-08 22:00:22 +00:00
{
2023-10-06 21:18:53 +00:00
std : : filesystem : : path path ( fname . c_str ( ) ) ;
2023-06-13 22:40:45 +00:00
SearchForFiles ( path . make_preferred ( ) , flist , false ) ;
2021-06-08 22:00:22 +00:00
}
else
{
SConversion conv = { } ;
2023-10-06 21:18:53 +00:00
std : : filesystem : : path path ( fname . c_str ( ) ) ;
2023-06-13 22:40:45 +00:00
conv . szSrc = path . make_preferred ( ) . native ( ) ;
2021-06-08 22:00:22 +00:00
flist . push_back ( conv ) ;
}
}
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
}
2023-03-27 23:02:41 +00:00
void PrintLogo ( bool versionOnly )
2016-09-12 23:39:26 +00:00
{
2020-08-15 22:57:39 +00:00
wchar_t version [ 32 ] = { } ;
wchar_t appName [ _MAX_PATH ] = { } ;
2023-06-13 22:40:45 +00:00
if ( GetModuleFileNameW ( nullptr , appName , _MAX_PATH ) )
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 ) ;
}
2023-03-27 23:02:41 +00:00
if ( versionOnly )
{
wprintf ( L " texassemble version %ls \n " , version ) ;
}
else
{
wprintf ( L " Microsoft (R) DirectX Texture Assembler [DirectXTex] Version %ls \n " , version ) ;
wprintf ( L " Copyright (C) Microsoft Corp. \n " ) ;
# ifdef _DEBUG
wprintf ( L " *** Debug build *** \n " ) ;
# endif
wprintf ( L " \n " ) ;
}
2016-09-12 23:39:26 +00:00
}
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 ) ;
2023-05-17 18:38:08 +00:00
for ( wchar_t * ptr = desc ; * ptr ! = 0 ; + + ptr )
{
if ( * ptr = = L ' \r ' | | * ptr = = L ' \n ' )
{
* ptr = L ' ' ;
}
}
2021-04-01 07:59:57 +00:00
}
return desc ;
}
2016-08-22 18:26:36 +00:00
2016-09-12 23:39:26 +00:00
void PrintUsage ( )
{
2023-03-27 23:02:41 +00:00
PrintLogo ( false ) ;
2016-08-22 18:26:36 +00:00
2022-10-25 20:18:09 +00:00
static const wchar_t * const s_usage =
2023-03-27 23:02:41 +00:00
L " Usage: texassemble <command> <options> [--] <files> \n "
2022-10-25 20:18:09 +00:00
L " \n "
L " cube create cubemap \n "
L " volume create volume map \n "
L " array create texture array \n "
L " cubearray create cubemap array \n "
L " h-cross or v-cross create a cross image from a cubemap \n "
2022-11-05 00:42:27 +00:00
L " v-cross-fnz create a cross image flipping the -Z face \n "
L " h-tee create a 'T' image from a cubemap \n "
2022-10-25 20:18:09 +00:00
L " h-strip or v-strip create a strip image from a cubemap \n "
2022-11-20 18:47:30 +00:00
L " array-strip create a strip image from a 1D/2D array \n "
2022-10-25 20:18:09 +00:00
L " merge create texture from rgb image and alpha image \n "
L " gif create array from animated gif \n "
2022-11-20 18:47:30 +00:00
L " cube-from-hc create cubemap from a h-cross image \n "
L " cube-from-vc create cubemap from a v-cross image \n "
L " cube-from-vc-fnz create cubemap from a v-cross image flipping the -Z face \n "
L " cube-from-ht create cubemap from a h-tee image \n "
L " cube-from-hs create cubemap from a h-strip image \n "
L " cube-from-vs create cubemap from a v-strip image \n "
2022-10-25 20:18:09 +00:00
L " \n "
L " -r wildcard filename search is recursive \n "
L " -flist <filename> use text file with a list of input files (one per line) \n "
L " -w <n> width \n "
L " -h <n> height \n "
L " -f <format> format \n "
L " -if <filter> image filtering \n "
L " -srgb{i|o} sRGB {input, output} \n "
L " -o <filename> output filename \n "
L " -l force output filename to lower case \n "
L " -y overwrite existing output file (if any) \n "
L " -sepalpha resize alpha channel separately from color channels \n "
L " -nowic Force non-WIC filtering \n "
L " -wrap, -mirror texture addressing mode (wrap, mirror, or clamp) \n "
L " -alpha convert premultiplied alpha to straight alpha \n "
L " -dx10 Force use of 'DX10' extended header \n "
L " -nologo suppress copyright message \n "
L " -fl <feature-level> Set maximum feature level target (defaults to 11.0) \n "
L " -tonemap Apply a tonemap operator based on maximum luminance \n "
L " \n "
L " (gif only) \n "
L " -bgcolor Use background color instead of transparency \n "
L " \n "
L " (merge only) \n "
L " -swizzle <rgba> Select channels for merge (defaults to rgbB) \n "
L " \n "
L " (cube, volume, array, cubearray, merge only) \n "
2023-03-27 23:02:41 +00:00
L " -stripmips Use only base image from input dds files \n "
L " \n "
L " '-- ' is needed if any input filepath starts with the '-' or '/' character \n " ;
2022-10-25 20:18:09 +00:00
wprintf ( L " %ls " , s_usage ) ;
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 ) ;
2024-01-20 19:02:19 +00:00
# ifdef USE_OPENEXR
2018-02-08 02:14:42 +00:00
case CODEC_EXR :
return SaveToEXRFile ( img , szOutputFile ) ;
2024-01-20 19:02:19 +00:00
# endif
# ifdef USE_LIBJPEG
case CODEC_JPEG :
return SaveToJPEGFile ( img , szOutputFile ) ;
# endif
# ifdef USE_LIBPNG
case CODEC_PNG :
return SaveToPNGFile ( img , szOutputFile ) ;
# endif
2018-02-08 02:14:42 +00:00
default :
2022-03-02 22:25:27 +00:00
{
2022-04-04 22:03:02 +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 ;
2022-03-02 22:25:27 +00:00
}
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
2023-06-13 22:40:45 +00:00
std : : wstring outputFile ;
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 ;
}
2023-03-27 23:02:41 +00:00
if ( ( ' - ' = = argv [ 1 ] [ 0 ] ) & & ( ' - ' = = argv [ 1 ] [ 1 ] ) )
{
if ( ! _wcsicmp ( argv [ 1 ] , L " --version " ) )
{
PrintLogo ( true ) ;
return 0 ;
}
else if ( ! _wcsicmp ( argv [ 1 ] , L " --help " ) )
{
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 :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2016-09-24 08:06:54 +00:00
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 :
2022-11-20 18:47:30 +00:00
case CMD_CUBE_FROM_HC :
case CMD_CUBE_FROM_VC :
case CMD_CUBE_FROM_VC_FNZ :
case CMD_CUBE_FROM_HT :
case CMD_CUBE_FROM_HS :
case CMD_CUBE_FROM_VS :
2024-02-15 06:25:11 +00:00
case CMD_FROM_MIPS :
2016-09-24 08:06:54 +00:00
break ;
default :
2022-11-20 18:47:30 +00:00
wprintf ( L " Must use one of: " ) ;
PrintList ( 4 , g_pCommands ) ;
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 ;
2023-03-27 23:02:41 +00:00
bool allowOpts = true ;
2016-09-25 21:09:14 +00:00
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 ] ;
2023-03-27 23:02:41 +00:00
if ( allowOpts
& & ( ' - ' = = pArg [ 0 ] ) & & ( ' - ' = = pArg [ 1 ] ) )
{
if ( pArg [ 2 ] = = 0 )
{
// "-- " is the POSIX standard for "end of options" marking to escape the '-' and '/' characters at the start of filepaths.
allowOpts = false ;
}
else if ( ! _wcsicmp ( pArg , L " --version " ) )
{
PrintLogo ( true ) ;
return 0 ;
}
else if ( ! _wcsicmp ( pArg , L " --help " ) )
{
PrintUsage ( ) ;
return 0 ;
}
else
{
wprintf ( L " Unknown option: %ls \n " , pArg ) ;
return 1 ;
}
}
else if ( allowOpts
& & ( ( ' - ' = = 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 :
2022-04-04 22:03:02 +00:00
{
2023-03-27 23:02:41 +00:00
std : : filesystem : : path path ( pValue ) ;
2023-06-13 22:40:45 +00:00
outputFile = path . make_preferred ( ) . native ( ) ;
2016-09-24 08:06:54 +00:00
2023-06-13 22:40:45 +00:00
fileType = LookupByName ( path . extension ( ) . c_str ( ) , g_pExtFileTypes ) ;
2016-09-24 08:06:54 +00:00
2022-04-04 22:03:02 +00:00
switch ( dwCommand )
2016-09-24 08:06:54 +00:00
{
2022-04-04 22:03:02 +00:00
case CMD_H_CROSS :
case CMD_V_CROSS :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2022-04-04 22:03:02 +00:00
case CMD_H_STRIP :
case CMD_V_STRIP :
case CMD_MERGE :
case CMD_ARRAY_STRIP :
2024-02-15 06:25:11 +00:00
case CMD_FROM_MIPS :
2022-04-04 22:03:02 +00:00
break ;
default :
if ( fileType ! = CODEC_DDS )
{
wprintf ( L " Assembled output file must be a dds \n " ) ;
return 1 ;
}
2016-09-24 08:06:54 +00:00
}
2022-04-04 22:03:02 +00:00
break ;
2016-09-24 08:06:54 +00:00
}
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 :
{
2023-03-27 23:02:41 +00:00
std : : filesystem : : path path ( pValue ) ;
std : : wifstream inFile ( path . make_preferred ( ) . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
if ( ! inFile )
{
wprintf ( L " Error opening -flist file %ls \n " , pValue ) ;
return 1 ;
}
2019-09-14 00:31:09 +00:00
2022-04-04 22:03:02 +00:00
inFile . imbue ( std : : locale : : classic ( ) ) ;
2021-10-28 18:12:16 +00:00
2022-04-04 22:03:02 +00:00
ProcessFileList ( inFile , conversion ) ;
}
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 ( ) ;
2023-03-27 23:02:41 +00:00
std : : filesystem : : path path ( pArg ) ;
2023-06-13 22:40:45 +00:00
SearchForFiles ( path . make_preferred ( ) , conversion , ( dwOptions & ( 1 < < OPT_RECURSIVE ) ) ! = 0 ) ;
2016-09-13 04:54:08 +00:00
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 = { } ;
2023-03-27 23:02:41 +00:00
std : : filesystem : : path path ( pArg ) ;
2023-06-13 22:40:45 +00:00
conv . szSrc = path . make_preferred ( ) . native ( ) ;
2016-08-22 18:26:36 +00:00
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 ) )
2023-03-27 23:02:41 +00:00
PrintLogo ( false ) ;
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_H_CROSS :
case CMD_V_CROSS :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2016-09-24 08:06:54 +00:00
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 :
2022-11-20 18:47:30 +00:00
case CMD_CUBE_FROM_HC :
case CMD_CUBE_FROM_VC :
case CMD_CUBE_FROM_VC_FNZ :
case CMD_CUBE_FROM_HT :
case CMD_CUBE_FROM_HS :
case CMD_CUBE_FROM_VS :
2016-09-24 08:06:54 +00:00
if ( conversion . size ( ) > 1 )
{
2022-11-20 18:47:30 +00:00
wprintf ( L " ERROR: cross/strip/gif/cube-from-* 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
{
2023-06-13 22:40:45 +00:00
std : : filesystem : : path curpath ( conversion . front ( ) . szSrc ) ;
2016-08-22 18:26:36 +00:00
2023-06-13 22:40:45 +00:00
wprintf ( L " reading %ls " , curpath . c_str ( ) ) ;
2018-02-09 22:32:57 +00:00
fflush ( stdout ) ;
2016-08-22 18:26:36 +00:00
2023-06-13 22:40:45 +00:00
if ( outputFile . empty ( ) )
2018-02-09 22:32:57 +00:00
{
2023-06-13 22:40:45 +00:00
outputFile = curpath . stem ( ) . concat ( L " .dds " ) . native ( ) ;
2016-08-22 18:26:36 +00:00
}
2023-06-13 22:40:45 +00:00
hr = LoadAnimatedGif ( curpath . c_str ( ) , loadedImages , ( dwOptions & ( 1 < < OPT_GIF_BGCOLOR ) ) ! = 0 ) ;
2018-02-09 22:32:57 +00:00
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
{
2024-02-15 06:25:11 +00:00
size_t conversionIndex = 0 ;
2018-02-09 22:32:57 +00:00
for ( auto pConv = conversion . begin ( ) ; pConv ! = conversion . end ( ) ; + + pConv )
2016-08-22 18:26:36 +00:00
{
2023-06-13 22:40:45 +00:00
std : : filesystem : : path curpath ( pConv - > szSrc ) ;
auto const ext = curpath . extension ( ) ;
2018-02-09 22:32:57 +00:00
// Load source image
if ( pConv ! = conversion . begin ( ) )
wprintf ( L " \n " ) ;
2023-06-13 22:40:45 +00:00
else if ( outputFile . empty ( ) )
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 :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2018-02-09 22:32:57 +00:00
case CMD_H_STRIP :
case CMD_V_STRIP :
2019-01-29 00:26:46 +00:00
case CMD_ARRAY_STRIP :
2023-06-13 22:40:45 +00:00
outputFile = curpath . stem ( ) . concat ( L " .bmp " ) . native ( ) ;
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
default :
2023-06-13 22:40:45 +00:00
if ( _wcsicmp ( curpath . extension ( ) . c_str ( ) , L " .dds " ) = = 0 )
2018-02-09 22:32:57 +00:00
{
wprintf ( L " ERROR: Need to specify output file via -o \n " ) ;
return 1 ;
}
2023-06-13 22:40:45 +00:00
outputFile = curpath . stem ( ) . concat ( L " .dds " ) . native ( ) ;
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
2023-06-13 22:40:45 +00:00
wprintf ( L " reading %ls " , curpath . c_str ( ) ) ;
2018-02-09 22:32:57 +00:00
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 :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2018-02-09 22:32:57 +00:00
case CMD_H_STRIP :
case CMD_V_STRIP :
2023-06-13 22:40:45 +00:00
if ( _wcsicmp ( ext . c_str ( ) , L " .dds " ) = = 0 )
2018-02-09 22:32:57 +00:00
{
2023-06-13 22:40:45 +00:00
hr = LoadFromDDSFile ( curpath . c_str ( ) , 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 :
2023-06-13 22:40:45 +00:00
if ( _wcsicmp ( ext . c_str ( ) , L " .dds " ) = = 0 )
2019-01-29 00:09:14 +00:00
{
2023-06-13 22:40:45 +00:00
hr = LoadFromDDSFile ( curpath . c_str ( ) , 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 :
2023-06-13 22:40:45 +00:00
if ( _wcsicmp ( ext . c_str ( ) , L " .dds " ) = = 0 )
2016-09-24 08:06:54 +00:00
{
2023-06-13 22:40:45 +00:00
hr = LoadFromDDSFile ( curpath . c_str ( ) , 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 ) )
{
2022-11-20 18:47:30 +00:00
switch ( dwCommand )
{
case CMD_CUBE :
case CMD_VOLUME :
case CMD_ARRAY :
case CMD_CUBEARRAY :
case CMD_MERGE :
wprintf ( L " \n ERROR: Can't assemble using input mips. To ignore mips, try again with -stripmips \n " ) ;
return 1 ;
default :
break ;
}
2021-03-04 08:21:44 +00:00
}
2016-09-24 08:06:54 +00:00
}
2023-06-13 22:40:45 +00:00
else if ( _wcsicmp ( ext . c_str ( ) , L " .tga " ) = = 0 )
2016-09-24 08:06:54 +00:00
{
2022-05-07 22:10:55 +00:00
TGA_FLAGS tgaFlags = ( IsBGR ( format ) ) ? TGA_FLAGS_BGR : TGA_FLAGS_NONE ;
2023-06-13 22:40:45 +00:00
hr = LoadFromTGAFile ( curpath . c_str ( ) , tgaFlags , & 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
}
2023-06-13 22:40:45 +00:00
else if ( _wcsicmp ( ext . c_str ( ) , L " .hdr " ) = = 0 )
2016-09-24 08:06:54 +00:00
{
2023-06-13 22:40:45 +00:00
hr = LoadFromHDRFile ( curpath . c_str ( ) , & 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
}
2022-04-04 22:03:02 +00:00
# ifdef USE_OPENEXR
2023-06-13 22:40:45 +00:00
else if ( _wcsicmp ( ext . c_str ( ) , L " .exr " ) = = 0 )
2016-10-02 19:44:07 +00:00
{
2023-06-13 22:40:45 +00:00
hr = LoadFromEXRFile ( curpath . c_str ( ) , & 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 ) ) ;
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
}
2022-04-04 22:03:02 +00:00
# endif
2024-01-20 19:02:19 +00:00
# ifdef USE_LIBJPEG
else if ( _wcsicmp ( ext . c_str ( ) , L " .jpg " ) = = 0 | | _wcsicmp ( ext . c_str ( ) , L " .jpeg " ) = = 0 )
{
hr = LoadFromJPEGFile ( curpath . c_str ( ) , & info , * image ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
}
# endif
# ifdef USE_LIBPNG
else if ( _wcsicmp ( ext . c_str ( ) , L " .png " ) = = 0 )
{
hr = LoadFromPNGFile ( curpath . c_str ( ) , & info , * image ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
}
# endif
2018-02-09 22:32:57 +00:00
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
2023-06-13 22:40:45 +00:00
hr = LoadFromWICFile ( curpath . c_str ( ) , 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 */ )
{
2023-06-13 22:40:45 +00:00
if ( _wcsicmp ( ext . c_str ( ) , L " .heic " ) = = 0 | | _wcsicmp ( ext . c_str ( ) , L " .heif " ) = = 0 )
2022-03-02 22:25:27 +00:00
{
wprintf ( L " INFO: This format requires installing the HEIF Image Extensions - https://aka.ms/heif \n " ) ;
}
2023-06-13 22:40:45 +00:00
else if ( _wcsicmp ( ext . c_str ( ) , L " .webp " ) = = 0 )
2022-03-02 22:25:27 +00:00
{
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 ;
}
2024-02-15 06:25:11 +00:00
size_t targetWidth = width ;
size_t targetHeight = height ;
if ( dwCommand = = CMD_FROM_MIPS )
{
size_t mipdiv = 1 ;
for ( size_t i = 0 ; i < conversionIndex ; + + i )
{
mipdiv = mipdiv + mipdiv ;
}
targetWidth / = mipdiv ;
targetHeight / = mipdiv ;
if ( targetWidth = = 0 | | targetHeight = = 0 )
{
2024-02-15 19:13:53 +00:00
wprintf ( L " \n ERROR: Too many input mips provided. For the dimensions of the first mip provided, only %zu input mips can be used. \n " , conversionIndex ) ;
2024-02-15 06:25:11 +00:00
return 1 ;
}
}
if ( info . width ! = targetWidth | | info . height ! = targetHeight )
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-08-22 18:26:36 +00:00
2024-02-15 06:25:11 +00:00
hr = Resize ( image - > GetImages ( ) , image - > GetImageCount ( ) , image - > GetMetadata ( ) , targetWidth , targetHeight , dwFilter | dwFilterOpts , * timage . get ( ) ) ;
2018-02-09 22:32:57 +00:00
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
2024-02-15 06:25:11 +00:00
assert ( tinfo . width = = targetWidth & & tinfo . height = = targetHeight & & tinfo . mipLevels = = 1 ) ;
2018-02-09 22:32:57 +00:00
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
2022-04-04 22:03:02 +00:00
# ifndef NDEBUG
2018-02-09 22:32:57 +00:00
auto & tinfo = timage - > GetMetadata ( ) ;
2022-04-04 22:03:02 +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 ) ) ;
2024-02-15 06:25:11 +00:00
+ + conversionIndex ;
2018-02-09 22:32:57 +00:00
}
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 :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2016-09-24 08:06:54 +00:00
case CMD_H_STRIP :
case CMD_V_STRIP :
2018-02-09 22:32:57 +00:00
case CMD_GIF :
2022-11-20 18:47:30 +00:00
case CMD_CUBE_FROM_HC :
case CMD_CUBE_FROM_VC :
case CMD_CUBE_FROM_VC_FNZ :
case CMD_CUBE_FROM_HT :
case CMD_CUBE_FROM_HS :
case CMD_CUBE_FROM_VS :
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 :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
case CMD_H_TEE :
2016-09-24 08:06:54 +00:00
case CMD_H_STRIP :
case CMD_V_STRIP :
{
2022-04-04 22:03:02 +00:00
size_t twidth = 0 ;
size_t theight = 0 ;
2016-09-24 08:06:54 +00:00
switch ( dwCommand )
{
case CMD_H_CROSS :
2022-11-05 00:42:27 +00:00
case CMD_H_TEE :
2022-04-04 22:03:02 +00:00
twidth = width * 4 ;
theight = height * 3 ;
2016-09-24 08:06:54 +00:00
break ;
case CMD_V_CROSS :
2022-11-05 00:42:27 +00:00
case CMD_V_CROSS_FNZ :
2022-04-04 22:03:02 +00:00
twidth = width * 3 ;
theight = height * 4 ;
2016-09-24 08:06:54 +00:00
break ;
case CMD_H_STRIP :
2022-04-04 22:03:02 +00:00
twidth = width * 6 ;
theight = height ;
2016-09-24 08:06:54 +00:00
break ;
case CMD_V_STRIP :
2022-04-04 22:03:02 +00:00
twidth = width ;
theight = height * 6 ;
2016-09-24 08:06:54 +00:00
break ;
2019-07-06 06:48:39 +00:00
default :
break ;
2016-09-24 08:06:54 +00:00
}
2022-04-04 22:03:02 +00:00
ScratchImage result ;
hr = result . Initialize2D ( format , twidth , theight , 1 , 1 ) ;
2016-09-24 08:06:54 +00:00
if ( FAILED ( hr ) )
{
2022-04-04 22:03:02 +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 ;
}
2022-04-04 22:03:02 +00:00
auto src = loadedImages . cbegin ( ) ;
auto dest = result . GetImage ( 0 , 0 , 0 ) ;
2020-04-14 00:22:55 +00:00
2022-04-04 22:03:02 +00:00
for ( size_t index = 0 ; index < 6 ; + + index )
2016-09-24 08:06:54 +00:00
{
2022-04-04 22:03:02 +00:00
auto img = ( * src ) - > GetImage ( 0 , index , 0 ) ;
if ( ! img )
{
wprintf ( L " FAILED: Unexpected error \n " ) ;
return 1 ;
}
2016-09-24 08:06:54 +00:00
2022-04-04 22:03:02 +00:00
const Rect rect ( 0 , 0 , width , height ) ;
2016-09-24 08:06:54 +00:00
2022-04-04 22:03:02 +00:00
size_t offsetx = 0 ;
size_t offsety = 0 ;
2022-11-05 00:42:27 +00:00
TEX_FR_FLAGS flipRotate = TEX_FR_ROTATE0 ;
2016-09-24 08:06:54 +00:00
2022-04-04 22:03:02 +00:00
switch ( dwCommand )
{
case CMD_H_CROSS :
{
2022-11-05 00:42:27 +00:00
// +Y
// -X +Z +X -Z
// -Y
2016-09-24 08:06:54 +00:00
2022-04-04 22:03:02 +00:00
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 } ;
2018-02-08 02:14:42 +00:00
2022-04-04 22:03:02 +00:00
offsetx = s_offsetx [ index ] * width ;
offsety = s_offsety [ index ] * height ;
break ;
}
2021-02-25 08:57:58 +00:00
2022-04-04 22:03:02 +00:00
case CMD_V_CROSS :
{
2022-11-05 00:42:27 +00:00
// +Y
// -X +Z +X
// -Y
// -Z
static const size_t s_offsetx [ 6 ] = { 2 , 0 , 1 , 1 , 1 , 1 } ;
static const size_t s_offsety [ 6 ] = { 1 , 1 , 0 , 2 , 1 , 3 } ;
2022-04-04 22:03:02 +00:00
2022-11-05 00:42:27 +00:00
offsetx = s_offsetx [ index ] * width ;
offsety = s_offsety [ index ] * height ;
break ;
}
case CMD_V_CROSS_FNZ :
{
// +Y
// -X +Z +X
// -Y
// -Z (flipped H/V)
static const size_t s_offsetx [ 6 ] = { 2 , 0 , 1 , 1 , 1 , 1 } ;
static const size_t s_offsety [ 6 ] = { 1 , 1 , 0 , 2 , 1 , 3 } ;
offsetx = s_offsetx [ index ] * width ;
offsety = s_offsety [ index ] * height ;
if ( index = = 5 )
{
flipRotate = TEX_FR_ROTATE180 ;
}
break ;
}
case CMD_H_TEE :
{
// +Y
// +Z +X -Z -X
// -Y
static const size_t s_offsetx [ 6 ] = { 1 , 3 , 0 , 0 , 0 , 2 } ;
static const size_t s_offsety [ 6 ] = { 1 , 1 , 0 , 2 , 1 , 1 } ;
2019-09-14 00:31:09 +00:00
2022-04-04 22:03:02 +00:00
offsetx = s_offsetx [ index ] * width ;
offsety = s_offsety [ index ] * height ;
break ;
}
case CMD_H_STRIP :
2022-11-05 00:42:27 +00:00
// +X -X +Y -Y +Z -Z
2022-04-04 22:03:02 +00:00
offsetx = index * width ;
break ;
case CMD_V_STRIP :
2022-11-05 00:42:27 +00:00
// +X
// -X
// +Y
// -Y
// +Z
// -Z
2022-04-04 22:03:02 +00:00
offsety = index * height ;
break ;
default :
break ;
}
2022-11-05 00:42:27 +00:00
if ( flipRotate ! = TEX_FR_ROTATE0 )
{
ScratchImage tmp ;
hr = FlipRotate ( * img , flipRotate , tmp ) ;
if ( SUCCEEDED ( hr ) )
{
hr = CopyRectangle ( * tmp . GetImage ( 0 , 0 , 0 ) , rect , * dest , dwFilter | dwFilterOpts , offsetx , offsety ) ;
}
}
else
{
hr = CopyRectangle ( * img , rect , * dest , dwFilter | dwFilterOpts , offsetx , offsety ) ;
}
2022-04-04 22:03:02 +00:00
if ( FAILED ( hr ) )
2019-09-14 00:31:09 +00:00
{
2022-04-04 22:03:02 +00:00
wprintf ( L " FAILED building result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
2019-09-14 00:31:09 +00:00
}
2022-04-04 22:03:02 +00:00
}
2018-02-08 02:14:42 +00:00
2022-04-04 22:03:02 +00:00
// Write cross/strip
2023-06-13 22:40:45 +00:00
wprintf ( L " \n Writing %ls " , outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
2018-02-08 02:14:42 +00:00
2022-04-04 22:03:02 +00:00
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2023-06-13 22:40:45 +00:00
std : : transform ( outputFile . begin ( ) , outputFile . end ( ) , outputFile . begin ( ) , towlower ) ;
2022-04-04 22:03:02 +00:00
}
2020-04-14 00:22:55 +00:00
2022-04-04 22:03:02 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
2023-06-13 22:40:45 +00:00
if ( GetFileAttributesW ( outputFile . c_str ( ) ) ! = INVALID_FILE_ATTRIBUTES )
2022-04-04 22:03:02 +00:00
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
2023-06-13 22:40:45 +00:00
hr = SaveImageFile ( * dest , fileType , outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
if ( FAILED ( hr ) )
2018-02-08 02:14:42 +00:00
{
2022-04-04 22:03:02 +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 ;
}
2022-04-04 22:03:02 +00:00
break ;
2016-09-24 08:06:54 +00:00
}
2022-04-04 22:03:02 +00:00
case CMD_MERGE :
2016-09-24 08:06:54 +00:00
{
2022-04-04 22:03:02 +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 ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED [convert second input] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
2016-09-24 08:06:54 +00:00
2022-04-04 22:03:02 +00:00
const Image & img = * tempImage . GetImage ( 0 , 0 , 0 ) ;
2019-01-29 00:09:14 +00:00
2022-04-04 22:03:02 +00:00
// Merge with our first source image
const Image & rgb = * loadedImages [ 0 ] - > GetImage ( 0 , 0 , 0 ) ;
2019-01-29 00:09:14 +00:00
2022-04-04 22:03:02 +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 ] ) ;
2019-01-29 00:09:14 +00:00
2022-04-04 22:03:02 +00:00
ScratchImage result ;
hr = TransformImage ( rgb , [ & , zc , oc ] ( XMVECTOR * outPixels , const XMVECTOR * inPixels , size_t w , size_t y )
{
const XMVECTOR * inPixels2 = reinterpret_cast < XMVECTOR * > ( img . pixels + img . rowPitch * y ) ;
2019-01-29 00:09:14 +00:00
2022-04-04 22:03:02 +00:00
for ( size_t j = 0 ; j < w ; + + j )
{
XMVECTOR pixel = XMVectorPermute ( inPixels [ j ] , inPixels2 [ j ] ,
permuteElements [ 0 ] , permuteElements [ 1 ] , permuteElements [ 2 ] , permuteElements [ 3 ] ) ;
pixel = XMVectorSelect ( pixel , g_XMZero , zc ) ;
outPixels [ j ] = XMVectorSelect ( pixel , g_XMOne , oc ) ;
}
} , result ) ;
if ( FAILED ( hr ) )
2019-01-29 00:09:14 +00:00
{
2022-04-04 22:03:02 +00:00
wprintf ( L " FAILED [merge image] (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
2019-01-29 00:09:14 +00:00
return 1 ;
}
2022-04-04 22:03:02 +00:00
// Write merged texture
2023-06-13 22:40:45 +00:00
wprintf ( L " \n Writing %ls " , outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
2019-01-29 00:09:14 +00:00
2022-04-04 22:03:02 +00:00
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2023-06-13 22:40:45 +00:00
std : : transform ( outputFile . begin ( ) , outputFile . end ( ) , outputFile . begin ( ) , towlower ) ;
2022-04-04 22:03:02 +00:00
}
2019-01-29 00:09:14 +00:00
2022-04-04 22:03:02 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
2023-06-13 22:40:45 +00:00
if ( GetFileAttributesW ( outputFile . c_str ( ) ) ! = INVALID_FILE_ATTRIBUTES )
2022-04-04 22:03:02 +00:00
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
2019-01-29 00:09:14 +00:00
2023-06-13 22:40:45 +00:00
hr = SaveImageFile ( * result . GetImage ( 0 , 0 , 0 ) , fileType , outputFile . c_str ( ) ) ;
2019-01-29 00:09:14 +00:00
if ( FAILED ( hr ) )
{
2022-04-04 22:03:02 +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 ;
}
2022-04-04 22:03:02 +00:00
break ;
2019-01-29 00:09:14 +00:00
}
2022-04-04 22:03:02 +00:00
case CMD_ARRAY_STRIP :
2020-04-14 00:22:55 +00:00
{
2022-04-04 22:03:02 +00:00
const size_t twidth = width ;
const size_t theight = height * images ;
2020-04-14 00:22:55 +00:00
2022-04-04 22:03:02 +00:00
ScratchImage result ;
hr = result . Initialize2D ( format , twidth , theight , 1 , 1 ) ;
if ( FAILED ( hr ) )
2019-01-29 00:09:14 +00:00
{
2022-04-04 22:03:02 +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 ;
}
2022-04-04 22:03:02 +00:00
auto src = loadedImages . cbegin ( ) ;
auto dest = result . GetImage ( 0 , 0 , 0 ) ;
for ( size_t index = 0 ; index < images ; + + index )
2016-08-22 18:26:36 +00:00
{
2022-04-04 22:03:02 +00:00
auto img = ( * src ) - > GetImage ( 0 , index , 0 ) ;
if ( ! img )
{
wprintf ( L " FAILED: Unexpected error \n " ) ;
return 1 ;
}
const Rect rect ( 0 , 0 , width , height ) ;
constexpr 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 (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
2016-08-22 18:26:36 +00:00
}
2022-04-04 22:03:02 +00:00
// Write array strip
2023-06-13 22:40:45 +00:00
wprintf ( L " \n Writing %ls " , outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
2020-07-09 20:59:11 +00:00
{
2023-06-13 22:40:45 +00:00
std : : transform ( outputFile . begin ( ) , outputFile . end ( ) , outputFile . begin ( ) , towlower ) ;
2020-07-09 20:59:11 +00:00
}
2022-04-04 22:03:02 +00:00
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
2020-07-09 20:59:11 +00:00
{
2023-06-13 22:40:45 +00:00
if ( GetFileAttributesW ( outputFile . c_str ( ) ) ! = INVALID_FILE_ATTRIBUTES )
2022-04-04 22:03:02 +00:00
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
2020-07-09 20:59:11 +00:00
}
2023-06-13 22:40:45 +00:00
hr = SaveImageFile ( * dest , fileType , outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
if ( FAILED ( hr ) )
2020-07-09 20:59:11 +00:00
{
2022-04-04 22:03:02 +00:00
wprintf ( L " FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
2020-07-09 20:59:11 +00:00
}
break ;
2022-04-04 22:03:02 +00:00
}
2022-11-20 18:47:30 +00:00
case CMD_CUBE_FROM_HC :
case CMD_CUBE_FROM_VC :
case CMD_CUBE_FROM_VC_FNZ :
case CMD_CUBE_FROM_HT :
case CMD_CUBE_FROM_HS :
case CMD_CUBE_FROM_VS :
{
auto src = loadedImages . cbegin ( ) ;
auto img = ( * src ) - > GetImage ( 0 , 0 , 0 ) ;
size_t ratio_w = 1 ;
size_t ratio_h = 1 ;
switch ( dwCommand )
{
case CMD_CUBE_FROM_HC :
case CMD_CUBE_FROM_HT :
ratio_w = 4 ;
ratio_h = 3 ;
break ;
case CMD_CUBE_FROM_VC :
case CMD_CUBE_FROM_VC_FNZ :
ratio_w = 3 ;
ratio_h = 4 ;
break ;
case CMD_CUBE_FROM_HS :
ratio_w = 6 ;
break ;
case CMD_CUBE_FROM_VS :
ratio_h = 6 ;
break ;
default :
break ;
}
size_t twidth = width / ratio_w ;
size_t theight = height / ratio_h ;
if ( ( ( width % ratio_w ) ! = 0 ) | | ( ( height % ratio_h ) ! = 0 ) )
{
2022-11-20 19:47:21 +00:00
wprintf ( L " \n WARNING: %ls expects %zu:%zu aspect ratio \n " , g_pCommands [ dwCommand - 1 ] . name , ratio_w , ratio_h ) ;
2022-11-20 18:47:30 +00:00
}
if ( twidth > maxCube | | theight > maxCube )
{
wprintf ( L " \n WARNING: Target size exceeds maximum cube dimensions for feature level (%u) \n " , maxCube ) ;
}
ScratchImage result ;
hr = result . InitializeCube ( format , twidth , theight , 1 , 1 ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED setting up result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
for ( size_t index = 0 ; index < 6 ; + + index )
{
size_t offsetx = 0 ;
size_t offsety = 0 ;
TEX_FR_FLAGS flipRotate = TEX_FR_ROTATE0 ;
switch ( dwCommand )
{
case CMD_CUBE_FROM_HC :
{
// +Y
// -X +Z +X -Z
// -Y
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 ] * twidth ;
offsety = s_offsety [ index ] * theight ;
break ;
}
case CMD_CUBE_FROM_VC :
{
// +Y
// -X +Z +X
// -Y
// -Z
static const size_t s_offsetx [ 6 ] = { 2 , 0 , 1 , 1 , 1 , 1 } ;
static const size_t s_offsety [ 6 ] = { 1 , 1 , 0 , 2 , 1 , 3 } ;
offsetx = s_offsetx [ index ] * twidth ;
offsety = s_offsety [ index ] * theight ;
break ;
}
case CMD_CUBE_FROM_VC_FNZ :
{
// +Y
// -X +Z +X
// -Y
// -Z (flipped H/V)
static const size_t s_offsetx [ 6 ] = { 2 , 0 , 1 , 1 , 1 , 1 } ;
static const size_t s_offsety [ 6 ] = { 1 , 1 , 0 , 2 , 1 , 3 } ;
offsetx = s_offsetx [ index ] * twidth ;
offsety = s_offsety [ index ] * theight ;
if ( index = = 5 )
{
flipRotate = TEX_FR_ROTATE180 ;
}
break ;
}
case CMD_CUBE_FROM_HT :
{
// +Y
// +Z +X -Z -X
// -Y
static const size_t s_offsetx [ 6 ] = { 1 , 3 , 0 , 0 , 0 , 2 } ;
static const size_t s_offsety [ 6 ] = { 1 , 1 , 0 , 2 , 1 , 1 } ;
offsetx = s_offsetx [ index ] * twidth ;
offsety = s_offsety [ index ] * theight ;
break ;
}
case CMD_CUBE_FROM_HS :
// +X -X +Y -Y +Z -Z
offsetx = index * twidth ;
break ;
case CMD_CUBE_FROM_VS :
// +X
// -X
// +Y
// -Y
// +Z
// -Z
offsety = index * theight ;
break ;
default :
break ;
}
const Rect rect ( offsetx , offsety , twidth , theight ) ;
const Image * dest = result . GetImage ( 0 , index , 0 ) ;
hr = CopyRectangle ( * img , rect , * dest , dwFilter | dwFilterOpts , 0 , 0 ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED building result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
if ( flipRotate ! = TEX_FR_ROTATE0 )
{
ScratchImage tmp ;
hr = FlipRotate ( * dest , flipRotate , tmp ) ;
if ( SUCCEEDED ( hr ) )
{
hr = CopyRectangle ( * tmp . GetImage ( 0 , 0 , 0 ) , Rect ( 0 , 0 , twidth , theight ) , * dest , dwFilter | dwFilterOpts , 0 , 0 ) ;
}
}
}
// Write texture
2023-06-13 22:40:45 +00:00
wprintf ( L " \n Writing %ls " , outputFile . c_str ( ) ) ;
2022-11-20 18:47:30 +00:00
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2023-06-13 22:40:45 +00:00
std : : transform ( outputFile . begin ( ) , outputFile . end ( ) , outputFile . begin ( ) , towlower ) ;
2022-11-20 18:47:30 +00:00
}
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
2023-06-13 22:40:45 +00:00
if ( GetFileAttributesW ( outputFile . c_str ( ) ) ! = INVALID_FILE_ATTRIBUTES )
2022-11-20 18:47:30 +00:00
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
hr = SaveToDDSFile ( result . GetImages ( ) , result . GetImageCount ( ) , result . GetMetadata ( ) ,
( dwOptions & ( 1 < < OPT_USE_DX10 ) ) ? ( DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2 ) : DDS_FLAGS_NONE ,
2023-06-13 22:40:45 +00:00
outputFile . c_str ( ) ) ;
2022-11-20 18:47:30 +00:00
if ( FAILED ( hr ) )
{
wprintf ( L " \n FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
break ;
}
2024-02-15 06:25:11 +00:00
case CMD_FROM_MIPS :
{
auto src = loadedImages . cbegin ( ) ;
ScratchImage result ;
hr = result . Initialize2D ( format , width , height , 1 , images ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED setting up result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
size_t mipdiv = 1 ;
size_t index = 0 ;
for ( auto it = src ; it ! = loadedImages . cend ( ) ; + + it )
{
auto dest = result . GetImage ( index , 0 , 0 ) ;
const ScratchImage * simage = it - > get ( ) ;
assert ( simage ! = nullptr ) ;
const Image * img = simage - > GetImage ( 0 , 0 , 0 ) ;
assert ( img ! = nullptr ) ;
hr = CopyRectangle ( * img , Rect ( 0 , 0 , width / mipdiv , height / mipdiv ) , * dest , dwFilter | dwFilterOpts , 0 , 0 ) ;
if ( FAILED ( hr ) )
{
wprintf ( L " FAILED building result image (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
index + + ;
mipdiv * = 2 ;
}
// Write texture2D
2024-02-15 19:13:53 +00:00
wprintf ( L " \n Writing %ls " , outputFile . c_str ( ) ) ;
2024-02-15 06:25:11 +00:00
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2024-02-15 19:13:53 +00:00
std : : transform ( outputFile . begin ( ) , outputFile . end ( ) , outputFile . begin ( ) , towlower ) ;
2024-02-15 06:25:11 +00:00
}
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
2024-02-15 19:13:53 +00:00
if ( GetFileAttributesW ( outputFile . c_str ( ) ) ! = INVALID_FILE_ATTRIBUTES )
2024-02-15 06:25:11 +00:00
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
hr = SaveToDDSFile ( result . GetImages ( ) , result . GetImageCount ( ) , result . GetMetadata ( ) ,
( dwOptions & ( 1 < < OPT_USE_DX10 ) ) ? ( DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2 ) : DDS_FLAGS_NONE ,
2024-02-15 19:13:53 +00:00
outputFile . c_str ( ) ) ;
2024-02-15 06:25:11 +00:00
if ( FAILED ( hr ) )
{
wprintf ( L " \n FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
break ;
}
2022-11-20 18:47:30 +00:00
2022-04-04 22:03:02 +00:00
default :
{
std : : vector < Image > imageArray ;
imageArray . reserve ( images ) ;
2020-07-09 20:59:11 +00:00
2022-04-04 22:03:02 +00:00
for ( auto it = loadedImages . cbegin ( ) ; it ! = loadedImages . cend ( ) ; + + it )
2020-07-09 20:59:11 +00:00
{
2022-04-04 22:03:02 +00:00
const ScratchImage * simage = it - > get ( ) ;
assert ( simage ! = nullptr ) ;
for ( size_t j = 0 ; j < simage - > GetMetadata ( ) . arraySize ; + + j )
{
const Image * img = simage - > GetImage ( 0 , j , 0 ) ;
assert ( img ! = nullptr ) ;
imageArray . push_back ( * img ) ;
}
2020-07-09 20:59:11 +00:00
}
2022-04-04 22:03:02 +00:00
switch ( dwCommand )
2020-07-09 20:59:11 +00:00
{
2022-04-04 22:03:02 +00:00
case CMD_CUBE :
if ( imageArray [ 0 ] . width > maxCube | | imageArray [ 0 ] . height > maxCube )
{
wprintf ( L " \n WARNING: Target size exceeds maximum cube dimensions for feature level (%u) \n " , maxCube ) ;
}
break ;
2020-07-09 20:59:11 +00:00
2022-04-04 22:03:02 +00:00
case CMD_VOLUME :
if ( imageArray [ 0 ] . width > maxVolume | | imageArray [ 0 ] . height > maxVolume | | imageArray . size ( ) > maxVolume )
{
wprintf ( L " \n WARNING: Target size exceeds volume extent for feature level (%u) \n " , maxVolume ) ;
}
break ;
2016-08-22 18:26:36 +00:00
2022-04-04 22:03:02 +00:00
case CMD_ARRAY :
if ( imageArray [ 0 ] . width > maxSize | | imageArray [ 0 ] . height > maxSize | | imageArray . size ( ) > maxArray )
{
wprintf ( L " \n WARNING: Target size exceeds maximum size for feature level (size %u, array %u) \n " , maxSize , maxArray ) ;
}
break ;
2016-08-22 18:26:36 +00:00
2022-04-04 22:03:02 +00:00
case CMD_CUBEARRAY :
if ( imageArray [ 0 ] . width > maxCube | | imageArray [ 0 ] . height > maxCube | | imageArray . size ( ) > maxArray )
{
wprintf ( L " \n WARNING: Target size exceeds maximum cube dimensions for feature level (size %u, array %u) \n " , maxCube , maxArray ) ;
}
break ;
2019-07-06 06:48:39 +00:00
2022-04-04 22:03:02 +00:00
default :
if ( imageArray [ 0 ] . width > maxSize | | imageArray [ 0 ] . height > maxSize )
{
wprintf ( L " \n WARNING: Target size exceeds maximum size for feature level (%u) \n " , maxSize ) ;
}
break ;
}
2016-08-22 18:26:36 +00:00
2022-04-04 22:03:02 +00:00
ScratchImage result ;
switch ( dwCommand )
{
case CMD_VOLUME :
hr = result . Initialize3DFromImages ( & imageArray [ 0 ] , imageArray . size ( ) ) ;
break ;
2016-08-22 18:26:36 +00:00
2022-04-04 22:03:02 +00:00
case CMD_ARRAY :
case CMD_GIF :
hr = result . InitializeArrayFromImages ( & imageArray [ 0 ] , imageArray . size ( ) , ( dwOptions & ( 1 < < OPT_USE_DX10 ) ) ! = 0 ) ;
break ;
2016-08-22 18:26:36 +00:00
2022-04-04 22:03:02 +00:00
case CMD_CUBE :
case CMD_CUBEARRAY :
hr = result . InitializeCubeFromImages ( & imageArray [ 0 ] , imageArray . size ( ) ) ;
break ;
2020-04-14 00:22:55 +00:00
2022-04-04 22:03:02 +00:00
default :
break ;
}
if ( FAILED ( hr ) )
2016-09-24 08:06:54 +00:00
{
2022-04-04 22:03:02 +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 ;
}
2022-04-04 22:03:02 +00:00
// Write texture
2023-06-13 22:40:45 +00:00
wprintf ( L " \n Writing %ls " , outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
PrintInfo ( result . GetMetadata ( ) ) ;
wprintf ( L " \n " ) ;
fflush ( stdout ) ;
if ( dwOptions & ( 1 < < OPT_TOLOWER ) )
{
2023-06-13 22:40:45 +00:00
std : : transform ( outputFile . begin ( ) , outputFile . end ( ) , outputFile . begin ( ) , towlower ) ;
2022-04-04 22:03:02 +00:00
}
if ( ~ dwOptions & ( 1 < < OPT_OVERWRITE ) )
{
2023-06-13 22:40:45 +00:00
if ( GetFileAttributesW ( outputFile . c_str ( ) ) ! = INVALID_FILE_ATTRIBUTES )
2022-04-04 22:03:02 +00:00
{
wprintf ( L " \n ERROR: Output file already exists, use -y to overwrite \n " ) ;
return 1 ;
}
}
hr = SaveToDDSFile ( result . GetImages ( ) , result . GetImageCount ( ) , result . GetMetadata ( ) ,
( dwOptions & ( 1 < < OPT_USE_DX10 ) ) ? ( DDS_FLAGS_FORCE_DX10_EXT | DDS_FLAGS_FORCE_DX10_EXT_MISC2 ) : DDS_FLAGS_NONE ,
2023-06-13 22:40:45 +00:00
outputFile . c_str ( ) ) ;
2022-04-04 22:03:02 +00:00
if ( FAILED ( hr ) )
{
wprintf ( L " \n FAILED (%08X%ls) \n " , static_cast < unsigned int > ( hr ) , GetErrorDesc ( hr ) ) ;
return 1 ;
}
break ;
2016-08-22 18:26:36 +00:00
}
}
return 0 ;
}