备注 :用了一下微软的这个开源代码,执行到:
ScopedObject<IWICBitmapDecoder> decoder;
HRESULT hr = pWIC->CreateDecoderFromFilename( fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder );
的时候就终止了,没有获取到相应的解码器decoder指向null,可是我有可以打开tga格式的文件的软件,这是否证明我有解码器呢?由于对解码这块不是很了解,果断不挣扎,暂时放弃这种方式。
现在创建纹理是使用:
D3DX11CreateShaderResourceViewFromFile(m_pd3dDevice, L"Lightning\\c001_07.dds", NULL, NULL, &mTexture, NULL);
这种方式的话就必须把其他格式的文件转换为dds文件。附件附上一个转换格式的软件,很小很好用。
总结:网上很多人都在困惑DX11获取纹理的方法,最好当然是什么格式的文件都支持比较好,这样也程序也显得健壮一些。但是,事情总不能像想的那么美满,暂时使用格式转换的方式解决。如果有路过的高手,请指点一下,谢谢!
正文:
对于3D渲染来说,纹理是一个极为常见的东西,而且一般图形格式的文件都可以作为纹理文件,在DX9和DX10的时候创建纹理是一个比较简单的操作。但是到DX11突然这种快捷就没了,D3DX淘汰也就算了,关键是D3DX里面没有支持11的纹理创建,想用淘汰货都用不了。
从这个现象其实可以看出微软的意图,过去的版本里微软或许比较在意用户的快捷,从而提供了很多快捷的方式。但是,这些快捷从某种意义上阻止了性能的提升,从而想使用DX做出更高性能的渲染引擎时,常常因为暴露的接口而变的隔靴搔痒。出于这些原因,微软在DX11以及以后的版本开始放权,这种放权导致D3DX的淘汰,也影响了包括效果框架,纹理加载之类的一系列的功能。纹理加载搬迁至DirectXTex 里面,它与效果框架一样,以一种开源代码块的方式,让用户自己组织加载纹理的工具类。
ID3D11Device :: CreateTexture2D 方法只能创建DDS格式的纹理,其他格式的纹理需要自己实现一个工具类。
1.调用CoCreateInstance创建成像工厂接口(IWICImagingFactory)的。CoCreateInstance是一个通用的创建单例的方法。第一步简单理解就是创建一个IWICImagingFactory对象。
2.调用IWICImagingFactory :: CreateDecoderFromFilename的方法来创建一个IWICBitmapDecoder对象从图像文件名 。创建一个位图解码器。
3.呼叫的IWICBitmapDecoder :: GetFrame方法的帧的图像检索IWICBitmapFrameDecode接口。获取位图的某一帧图像。
4.调用IWICBitmapSource :: GetPixelFormat方法(IWICBitmapFrameDecode接口继承来自IWICBitmapSource)获得的图像的像素格式。这里获取的像素格式最终会映射成DXGI的像素格式。
5.根据此表的像素格式转换到DXGI_FORMAT类型:
WIC像素格式 | 等效DXGI_FORMAT |
---|---|
GUID_WICPixelFormat128bppRGBAFloat | DXGI_FORMAT_R32G32B32A32_FLOAT |
GUID_WICPixelFormat64bppRGBAHalf | DXGI_FORMAT_R16G16B16A16_FLOAT |
GUID_WICPixelFormat64bppRGBA | DXGI_FORMAT_R16G16B16A16_UNORM |
GUID_WICPixelFormat32bppRGBA | DXGI_FORMAT_R8G8B8A8_UNORM |
GUID_WICPixelFormat32bppBGRA | DXGI_FORMAT_B8G8R8A8_UNORM(DXGI 1.1) |
GUID_WICPixelFormat32bppBGR | DXGI_FORMAT_B8G8R8X8_UNORM(DXGI 1.1) |
GUID_WICPixelFormat32bppRGBA1010102XR | DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM(DXGI 1.1) |
GUID_WICPixelFormat32bppRGBA1010102 | DXGI_FORMAT_R10G10B10A2_UNORM |
GUID_WICPixelFormat32bppRGBE | DXGI_FORMAT_R9G9B9E5_SHAREDEXP |
GUID_WICPixelFormat16bppBGRA5551 | DXGI_FORMAT_B5G5R5A1_UNORM(DXGI 1.2) |
GUID_WICPixelFormat16bppBGR565 | DXGI_FORMAT_B5G6R5_UNORM(DXGI 1.2) |
GUID_WICPixelFormat32bppGrayFloat | DXGI_FORMAT_R32_FLOAT * |
GUID_WICPixelFormat16bppGrayHalf | DXGI_FORMAT_R16_FLOAT * |
GUID_WICPixelFormat16bppGray | DXGI_FORMAT_R16_UNORM * |
GUID_WICPixelFormat8bppGray | DXGI_FORMAT_R8_UNORM * |
GUID_WICPixelFormat8bppAlpha | DXGI_FORMAT_A8_UNORM |
GUID_WICPixelFormat96bppRGBFloat(Windows 8的WIC) | DXGI_FORMAT_R32G32B32_FLOAT |
*的单信道的DXGI格式都是红色通道,所以你需要HLSL着色器碎冰鸡尾酒。存款准备金率等,使这些灰度。微软自家的GUID和DXGI之间还得这么手动转换一下,这个真心没必要开源给我们,直接提供一个内置的转换方法不是更好么 - -。
6.调用IWICBitmapSource :: CopyPixels方法来复制到缓冲区中的图像的像素。使用的DXGI_FORMAT,类型和缓冲器初始化2D纹理资源和着色器资源视图对象。为神马第四步和第五步要大费周章的获取格式,就是为了这一步用的,这一步获取的像素码就是咱们的纹理对象可以直接使用的了。
7.呼叫ID3D11Device :: CreateTexture2D方法来初始化的2D纹理资源。在这个调用中,传递的一个ID3D11Texture2D的接口指针的地址。我第一次看到这个方法的时候,就在想它的第二个参数肿么获取,原来绕这么大个圈获取的。从某种意义上来说,前面1-6只不过是微软提供的一种获取D3D11_SUBRESOURCE_DATA的方式,其实方式不限。
8.呼叫ID3D11Device :: CreateShaderResourceView方法来初始化着色器资源视图对象。传递一个NULL着色器资源视图描述(获得视图使用默认参数)或一个非NULL着色器资源视图描述(非默认的视图参数)。如果有必要,确定结构类型通过调用ID3D11Resource ::的getType和纹理格式通过调用ID3D11ShaderResourceView :: GetDesc。这一步基本上与创建纹理无关,但是这一步也说明了微软的一个意图,传递给着色器的资源类型变统一了,不清楚之前是肿么传递的 - -。
上述就是微软提供的开源的获取纹理的方法里面实现的几个主要过程,这样看代码的时候也不需要纠结了,微软这是要想菜鸟“Say NO”啊~~
WICTextureLoader.h
//-------------------------------------------------------------------------------------/ /的的文件:WICTextureLoader.h
/ /
/ /功能加载WIC图像,并为它创建一个Direct3D 11运行时纹理
/ /(自动生成mipmap的,如果可能的话)
/ /
/ /注意:假设应用程序已经调用CoInitializeEx的
/ /
/ /警告:CreateWICTexture *函数不是线程安全的如果给定一个d3dContext实例。
/ /
/ /注意:这些功能是用于创建简单的2D纹理的图像。
/ /更复杂的资源,DDSTextureLoader是一个很好的轻质运行时加载
/ /对于一个全功能的DDS文件的读者,作家,和纹理处理的管道看
/ /“Texconv”的样品和“DirectXTex的图书馆。
/ /
/ /此代码,并提供资讯“AS IS”不保证,明示或暗示的担保,包括但不限于
/ / 一个适销性和/或适用性的暗示的保证。
//--------------------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma once
#endif
#include <d3d11.h>
#pragma warning(push)
#pragma warning(disable : 4005)
#include <stdint.h>
#pragma warning(pop)
HRESULT CreateWICTextureFromMemory( _In_ ID3D11Device* d3dDevice,
_In_opt_ ID3D11DeviceContext* d3dContext,
_In_bytecount_(wicDataSize) const uint8_t* wicData,
_In_ size_t wicDataSize,
_Out_opt_ ID3D11Resource** texture,
_Out_opt_ ID3D11ShaderResourceView** textureView,
_In_ size_t maxsize = 0
);
HRESULT CreateWICTextureFromFile( _In_ ID3D11Device* d3dDevice,
_In_opt_ ID3D11DeviceContext* d3dContext,
_In_z_ const wchar_t* szFileName,
_Out_opt_ ID3D11Resource** texture,
_Out_opt_ ID3D11ShaderResourceView** textureView,
_In_ size_t maxsize = 0
);
WICTextureLoader.cpp :
/ / ------------------------------------------------ --------------------------------------
/ /文件:WICTextureLoader.cpp
/ /
/ /功能加载WIC图像,并为它创建一个Direct3D 11运行时纹理
/ /(自动生成mipmap的,如果可能的话)
/ /
/ /注意:假设应用程序已经调用CoInitializeEx的
/ /
/ /警告:CreateWICTexture *函数不是线程安全的如果给定一个d3dContext实例。
/ /
/ /注意:这些功能是用于创建简单的2D纹理的图像。
/ /更复杂的资源,DDSTextureLoader是一个很好的轻质运行时加载
/ /对于一个全功能的DDS文件的读者,作家,和纹理处理的管道看
/ /“Texconv”的样品和“DirectXTex的图书馆。
/ /
/ /我们可以加载到一个纹理阵列中的多帧图像(TIFF / GIF)
/ /现在,我们只需要加载的第一帧(注:DirectXTex支持多帧图像)
#include <dxgiformat.h>
#include <assert.h>
#pragma warning(push)
#pragma warning(disable : 4005)
#include <wincodec.h>
#pragma warning(pop)
#include <memory>
#include "WICTextureLoader.h"
#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS)
#define DXGI_1_2_FORMATS
#endif
//---------------------------------------------------------------------------------
template<class T> class ScopedObject
{
public:
explicit ScopedObject( T *p = 0 ) : _pointer(p) {}
~ScopedObject()
{
if ( _pointer )
{
_pointer->Release();
_pointer = nullptr;
}
}
bool IsNull() const { return (!_pointer); }
T& operator*() { return *_pointer; }
T* operator->() { return _pointer; }
T** operator&() { return &_pointer; }
void Reset(T *p = 0) { if ( _pointer ) { _pointer->Release(); } _pointer = p; }
T* Get() const { return _pointer; }
private:
ScopedObject(const ScopedObject&);
ScopedObject& operator=(const ScopedObject&);
T* _pointer;
};
//-------------------------------------------------------------------------------------
// WIC Pixel Format Translation Data
//-------------------------------------------------------------------------------------
struct WICTranslate
{
GUID wic;
DXGI_FORMAT format;
};
static WICTranslate g_WICFormats[] =
{
{ GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT },
{ GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT },
{ GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM },
{ GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM },
{ GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1
{ GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1
{ GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1
{ GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM },
{ GUID_WICPixelFormat32bppRGBE, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
#ifdef DXGI_1_2_FORMATS
{ GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM },
{ GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM },
#endif // DXGI_1_2_FORMATS
{ GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT },
{ GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT },
{ GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM },
{ GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM },
{ GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM },
#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
{ GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT },
#endif
};
//-------------------------------------------------------------------------------------
// WIC Pixel Format nearest conversion table
//-------------------------------------------------------------------------------------
struct WICConvert
{
GUID source;
GUID target;
};
static WICConvert g_WICConvert[] =
{
// Note target GUID in this conversion table must be one of those directly supported formats (above).
{ GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
{ GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT
#ifdef DXGI_1_2_FORMATS
{ GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM
#else
{ GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat16bppBGRA5551, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat16bppBGR565, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
#endif // DXGI_1_2_FORMATS
{ GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM
{ GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
{ GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
#endif
// We don't support n-channel formats
};
//--------------------------------------------------------------------------------------
static IWICImagingFactory* _GetWIC()
{
static IWICImagingFactory* s_Factory = nullptr;
if ( s_Factory )
return s_Factory;
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
(LPVOID*)&s_Factory
);
if ( FAILED(hr) )
{
s_Factory = nullptr;
return nullptr;
}
return s_Factory;
}
//---------------------------------------------------------------------------------
static DXGI_FORMAT _WICToDXGI( const GUID& guid )
{
for( size_t i=0; i < _countof(g_WICFormats); ++i )
{
if ( memcmp( &g_WICFormats[i].wic, &guid, sizeof(GUID) ) == 0 )
return g_WICFormats[i].format;
}
return DXGI_FORMAT_UNKNOWN;
}
//---------------------------------------------------------------------------------
static size_t _WICBitsPerPixel( REFGUID targetGuid )
{
IWICImagingFactory* pWIC = _GetWIC();
if ( !pWIC )
return 0;
ScopedObject<IWICComponentInfo> cinfo;
if ( FAILED( pWIC->CreateComponentInfo( targetGuid, &cinfo ) ) )
return 0;
WICComponentType type;
if ( FAILED( cinfo->GetComponentType( &type ) ) )
return 0;
if ( type != WICPixelFormat )
return 0;
ScopedObject<IWICPixelFormatInfo> pfinfo;
if ( FAILED( cinfo->QueryInterface( __uuidof(IWICPixelFormatInfo), reinterpret_cast<void**>( &pfinfo ) ) ) )
return 0;
UINT bpp;
if ( FAILED( pfinfo->GetBitsPerPixel( &bpp ) ) )
return 0;
return bpp;
}
//---------------------------------------------------------------------------------
static HRESULT CreateTextureFromWIC( _In_ ID3D11Device* d3dDevice,
_In_opt_ ID3D11DeviceContext* d3dContext,
_In_ IWICBitmapFrameDecode *frame,
_Out_opt_ ID3D11Resource** texture,
_Out_opt_ ID3D11ShaderResourceView** textureView,
_In_ size_t maxsize )
{
UINT width, height;
HRESULT hr = frame->GetSize( &width, &height );
if ( FAILED(hr) )
return hr;
assert( width > 0 && height > 0 );
if ( !maxsize )
{
// This is a bit conservative because the hardware could support larger textures than
// the Feature Level defined minimums, but doing it this way is much easier and more
// performant for WIC than the 'fail and retry' model used by DDSTextureLoader
switch( d3dDevice->GetFeatureLevel() )
{
case D3D_FEATURE_LEVEL_9_1:
case D3D_FEATURE_LEVEL_9_2:
maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
break;
case D3D_FEATURE_LEVEL_9_3:
maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
break;
case D3D_FEATURE_LEVEL_10_0:
case D3D_FEATURE_LEVEL_10_1:
maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
break;
default:
maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
break;
}
}
assert( maxsize > 0 );
UINT twidth, theight;
if ( width > maxsize || height > maxsize )
{
float ar = static_cast<float>(height) / static_cast<float>(width);
if ( width > height )
{
twidth = static_cast<UINT>( maxsize );
theight = static_cast<UINT>( static_cast<float>(maxsize) * ar );
}
else
{
theight = static_cast<UINT>( maxsize );
twidth = static_cast<UINT>( static_cast<float>(maxsize) / ar );
}
assert( twidth <= maxsize && theight <= maxsize );
}
else
{
twidth = width;
theight = height;
}
// Determine format
WICPixelFormatGUID pixelFormat;
hr = frame->GetPixelFormat( &pixelFormat );
if ( FAILED(hr) )
return hr;
WICPixelFormatGUID convertGUID;
memcpy( &convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID) );
size_t bpp = 0;
DXGI_FORMAT format = _WICToDXGI( pixelFormat );
if ( format == DXGI_FORMAT_UNKNOWN )
{
for( size_t i=0; i < _countof(g_WICConvert); ++i )
{
if ( memcmp( &g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID) ) == 0 )
{
memcpy( &convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID) );
format = _WICToDXGI( g_WICConvert[i].target );
assert( format != DXGI_FORMAT_UNKNOWN );
bpp = _WICBitsPerPixel( convertGUID );
break;
}
}
if ( format == DXGI_FORMAT_UNKNOWN )
return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
}
else
{
bpp = _WICBitsPerPixel( pixelFormat );
}
if ( !bpp )
return E_FAIL;
// Verify our target format is supported by the current device
// (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support)
UINT support = 0;
hr = d3dDevice->CheckFormatSupport( format, &support );
if ( FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D) )
{
// Fallback to RGBA 32-bit format which is supported by all devices
memcpy( &convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID) );
format = DXGI_FORMAT_R8G8B8A8_UNORM;
bpp = 32;
}
// Allocate temporary memory for image
size_t rowPitch = ( twidth * bpp + 7 ) / 8;
size_t imageSize = rowPitch * theight;
std::unique_ptr<uint8_t[]> temp( new uint8_t[ imageSize ] );
// Load image data
if ( memcmp( &convertGUID, &pixelFormat, sizeof(GUID) ) == 0
&& twidth == width
&& theight == height )
{
// No format conversion or resize needed
hr = frame->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() );
if ( FAILED(hr) )
return hr;
}
else if ( twidth != width || theight != height )
{
// Resize
IWICImagingFactory* pWIC = _GetWIC();
if ( !pWIC )
return E_NOINTERFACE;
ScopedObject<IWICBitmapScaler> scaler;
hr = pWIC->CreateBitmapScaler( &scaler );
if ( FAILED(hr) )
return hr;
hr = scaler->Initialize( frame, twidth, theight, WICBitmapInterpolationModeFant );
if ( FAILED(hr) )
return hr;
WICPixelFormatGUID pfScaler;
hr = scaler->GetPixelFormat( &pfScaler );
if ( FAILED(hr) )
return hr;
if ( memcmp( &convertGUID, &pfScaler, sizeof(GUID) ) == 0 )
{
// No format conversion needed
hr = scaler->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() );
if ( FAILED(hr) )
return hr;
}
else
{
ScopedObject<IWICFormatConverter> FC;
hr = pWIC->CreateFormatConverter( &FC );
if ( FAILED(hr) )
return hr;
hr = FC->Initialize( scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom );
if ( FAILED(hr) )
return hr;
hr = FC->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() );
if ( FAILED(hr) )
return hr;
}
}
else
{
// Format conversion but no resize
IWICImagingFactory* pWIC = _GetWIC();
if ( !pWIC )
return E_NOINTERFACE;
ScopedObject<IWICFormatConverter> FC;
hr = pWIC->CreateFormatConverter( &FC );
if ( FAILED(hr) )
return hr;
hr = FC->Initialize( frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom );
if ( FAILED(hr) )
return hr;
hr = FC->CopyPixels( 0, static_cast<UINT>( rowPitch ), static_cast<UINT>( imageSize ), temp.get() );
if ( FAILED(hr) )
return hr;
}
// See if format is supported for auto-gen mipmaps (varies by feature level)
bool autogen = false;
if ( d3dContext != 0 && textureView != 0 ) // Must have context and shader-view to auto generate mipmaps
{
UINT fmtSupport = 0;
hr = d3dDevice->CheckFormatSupport( format, &fmtSupport );
if ( SUCCEEDED(hr) && ( fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN ) )
{
autogen = true;
}
}
// Create texture
D3D11_TEXTURE2D_DESC desc;
desc.Width = twidth;
desc.Height = theight;
desc.MipLevels = (autogen) ? 0 : 1;
desc.ArraySize = 1;
desc.Format = format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = (autogen) ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : (D3D11_BIND_SHADER_RESOURCE);
desc.CPUAccessFlags = 0;
desc.MiscFlags = (autogen) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = temp.get();
initData.SysMemPitch = static_cast<UINT>( rowPitch );
initData.SysMemSlicePitch = static_cast<UINT>( imageSize );
ID3D11Texture2D* tex = nullptr;
hr = d3dDevice->CreateTexture2D( &desc, (autogen) ? nullptr : &initData, &tex );
if ( SUCCEEDED(hr) && tex != 0 )
{
if (textureView != 0)
{
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
memset( &SRVDesc, 0, sizeof( SRVDesc ) );
SRVDesc.Format = format;
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1;
hr = d3dDevice->CreateShaderResourceView( tex, &SRVDesc, textureView );
if ( FAILED(hr) )
{
tex->Release();
return hr;
}
if ( autogen )
{
assert( d3dContext != 0 );
d3dContext->UpdateSubresource( tex, 0, nullptr, temp.get(), static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize) );
d3dContext->GenerateMips( *textureView );
}
}
if (texture != 0)
{
*texture = tex;
}
else
{
#if defined(_DEBUG) || defined(PROFILE)
tex->SetPrivateData( WKPDID_D3DDebugObjectName,
sizeof("WICTextureLoader")-1,
"WICTextureLoader"
);
#endif
tex->Release();
}
}
return hr;
}
//--------------------------------------------------------------------------------------
HRESULT CreateWICTextureFromMemory( _In_ ID3D11Device* d3dDevice,
_In_opt_ ID3D11DeviceContext* d3dContext,
_In_bytecount_(wicDataSize) const uint8_t* wicData,
_In_ size_t wicDataSize,
_Out_opt_ ID3D11Resource** texture,
_Out_opt_ ID3D11ShaderResourceView** textureView,
_In_ size_t maxsize
)
{
if (!d3dDevice || !wicData || (!texture && !textureView))
{
return E_INVALIDARG;
}
if ( !wicDataSize )
{
return E_FAIL;
}
#ifdef _M_AMD64
if ( wicDataSize > 0xFFFFFFFF )
return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE );
#endif
IWICImagingFactory* pWIC = _GetWIC();
if ( !pWIC )
return E_NOINTERFACE;
// Create input stream for memory
ScopedObject<IWICStream> stream;
HRESULT hr = pWIC->CreateStream( &stream );
if ( FAILED(hr) )
return hr;
hr = stream->InitializeFromMemory( const_cast<uint8_t*>( wicData ), static_cast<DWORD>( wicDataSize ) );
if ( FAILED(hr) )
return hr;
// Initialize WIC
ScopedObject<IWICBitmapDecoder> decoder;
hr = pWIC->CreateDecoderFromStream( stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder );
if ( FAILED(hr) )
return hr;
ScopedObject<IWICBitmapFrameDecode> frame;
hr = decoder->GetFrame( 0, &frame );
if ( FAILED(hr) )
return hr;
hr = CreateTextureFromWIC( d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize );
if ( FAILED(hr))
return hr;
#if defined(_DEBUG) || defined(PROFILE)
if (texture != 0 && *texture != 0)
{
(*texture)->SetPrivateData( WKPDID_D3DDebugObjectName,
sizeof("WICTextureLoader")-1,
"WICTextureLoader"
);
}
if (textureView != 0 && *textureView != 0)
{
(*textureView)->SetPrivateData( WKPDID_D3DDebugObjectName,
sizeof("WICTextureLoader")-1,
"WICTextureLoader"
);
}
#endif
return hr;
}
//--------------------------------------------------------------------------------------
HRESULT CreateWICTextureFromFile( _In_ ID3D11Device* d3dDevice,
_In_opt_ ID3D11DeviceContext* d3dContext,
_In_z_ const wchar_t* fileName,
_Out_opt_ ID3D11Resource** texture,
_Out_opt_ ID3D11ShaderResourceView** textureView,
_In_ size_t maxsize )
{
if (!d3dDevice || !fileName || (!texture && !textureView))
{
return E_INVALIDARG;
}
IWICImagingFactory* pWIC = _GetWIC();
if ( !pWIC )
return E_NOINTERFACE;
// Initialize WIC
ScopedObject<IWICBitmapDecoder> decoder;
HRESULT hr = pWIC->CreateDecoderFromFilename( fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder );
if ( FAILED(hr) )
return hr;
ScopedObject<IWICBitmapFrameDecode> frame;
hr = decoder->GetFrame( 0, &frame );
if ( FAILED(hr) )
return hr;
hr = CreateTextureFromWIC( d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize );
if ( FAILED(hr))
return hr;
#if defined(_DEBUG) || defined(PROFILE)
if (texture != 0 || textureView != 0)
{
CHAR strFileA[MAX_PATH];
WideCharToMultiByte( CP_ACP,
WC_NO_BEST_FIT_CHARS,
fileName,
-1,
strFileA,
MAX_PATH,
nullptr,
FALSE
);
const CHAR* pstrName = strrchr( strFileA, '\\' );
if (!pstrName)
{
pstrName = strFileA;
}
else
{
pstrName++;
}
if (texture != 0 && *texture != 0)
{
(*texture)->SetPrivateData( WKPDID_D3DDebugObjectName,
static_cast<UINT>( strnlen_s(pstrName, MAX_PATH) ),
pstrName
);
}
if (textureView != 0 && *textureView != 0 )
{
(*textureView)->SetPrivateData( WKPDID_D3DDebugObjectName,
static_cast<UINT>( strnlen_s(pstrName, MAX_PATH) ),
pstrName
);
}
}
#endif
return hr;
}