//--------------------------------------------------------------------------------------
// File: DDSTextureLoader.cpp
//
// Functions for loading a DDS texture and creating a Direct3D runtime resource for it
//
// Note these functions are useful as a light-weight runtime loader for DDS files. For
// a full-featured DDS file reader, writer, and texture processing pipeline see
// the 'Texconv' sample and the 'DirectXTex' library.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkId=248926
// http://go.microsoft.com/fwlink/?LinkId=248929
//--------------------------------------------------------------------------------------
#include "DDSTextureLoader.h"
#include <assert.h>
#include <algorithm>
#include <memory>
#if !defined(NO_D3D11_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) )
#pragma comment(lib,"dxguid.lib")
#endif
using namespace DirectX;
//--------------------------------------------------------------------------------------
// Macros
//--------------------------------------------------------------------------------------
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3) \
((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \
((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 ))
#endif /* defined(MAKEFOURCC) */
//--------------------------------------------------------------------------------------
// DDS file structure definitions
//
// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
//--------------------------------------------------------------------------------------
#pragma pack(push,1)
const uint32_t DDS_MAGIC = 0x20534444; // "DDS "
struct DDS_PIXELFORMAT
{
uint32_t size;
uint32_t flags;
uint32_t fourCC;
uint32_t RGBBitCount;
uint32_t RBitMask;
uint32_t GBitMask;
uint32_t BBitMask;
uint32_t ABitMask;
};
#define DDS_FOURCC 0x00000004 // DDPF_FOURCC
#define DDS_RGB 0x00000040 // DDPF_RGB
#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE
#define DDS_ALPHA 0x00000002 // DDPF_ALPHA
#define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV
#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH
#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
#define DDS_WIDTH 0x00000004 // DDSD_WIDTH
#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\
DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\
DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )
#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP
enum DDS_MISC_FLAGS2
{
DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,
};
struct DDS_HEADER
{
uint32_t size;
uint32_t flags;
uint32_t height;
uint32_t width;
uint32_t pitchOrLinearSize;
uint32_t depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags
uint32_t mipMapCount;
uint32_t reserved1[11];
DDS_PIXELFORMAT ddspf;
uint32_t caps;
uint32_t caps2;
uint32_t caps3;
uint32_t caps4;
uint32_t reserved2;
};
struct DDS_HEADER_DXT10
{
DXGI_FORMAT dxgiFormat;
uint32_t resourceDimension;
uint32_t miscFlag; // see D3D11_RESOURCE_MISC_FLAG
uint32_t arraySize;
uint32_t miscFlags2;
};
#pragma pack(pop)
//--------------------------------------------------------------------------------------
namespace
{
struct handle_closer { void operator()(HANDLE h) { if (h) CloseHandle(h); } };
typedef std::unique_ptr<void, handle_closer> ScopedHandle;
inline HANDLE safe_handle( HANDLE h ) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
template<UINT TNameLength>
inline void SetDebugObjectName(_In_ ID3D11DeviceChild* resource, _In_ const char (&name)[TNameLength])
{
#if defined(_DEBUG) || defined(PROFILE)
resource->SetPrivateData(WKPDID_D3DDebugObjectName, TNameLength - 1, name);
#else
UNREFERENCED_PARAMETER(resource);
UNREFERENCED_PARAMETER(name);
#endif
}
//--------------------------------------------------------------------------------------
HRESULT LoadTextureDataFromFile(
_In_z_ const wchar_t* fileName,
std::unique_ptr<uint8_t[]>& ddsData,
const DDS_HEADER** header,
const uint8_t** bitData,
size_t* bitSize)
{
if (!header || !bitData || !bitSize)
{
return E_POINTER;
}
// open the file
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
ScopedHandle hFile(safe_handle(CreateFile2(fileName,
GENERIC_READ,
FILE_SHARE_READ,
OPEN_EXISTING,
nullptr)));
#else
ScopedHandle hFile(safe_handle(CreateFileW(fileName,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr)));
#endif
if (!hFile)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// Get the file size
FILE_STANDARD_INFO fileInfo;
if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
{
return HRESULT_FROM_WIN32(GetLastError());
}
// File is too big for 32-bit allocation, so reject read
if (fileInfo.EndOfFile.HighPart > 0)
{
return E_FAIL;
}
// Need at least enough data to fill the header and magic number to be a valid DDS
if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t)))
{
return E_FAIL;
}
// create enough space for the file data
ddsData.reset(new (std::nothrow) uint8_t[fileInfo.EndOfFile.LowPart]);
if (!ddsData)
{
return E_OUTOFMEMORY;
}
// read the data in
DWORD BytesRead = 0;
if (!ReadFile(hFile.get(),
ddsData.get(),
fileInfo.EndOfFile.LowPart,
&BytesRead,
nullptr
))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (BytesRead < fileInfo.EndOfFile.LowPart)
{
return E_FAIL;
}
// DDS files always start with the same magic number ("DDS ")
uint32_t dwMagicNumber = *reinterpret_cast<const uint32_t*>(ddsData.get());
if (dwMagicNumber != DDS_MAGIC)
{
return E_FAIL;
}
auto hdr = reinterpret_cast<const DDS_HEADER*>(ddsData.get() + sizeof(uint32_t));
// Verify header to validate DDS file
if (hdr->size != sizeof(DDS_HEADER) ||
hdr->ddspf.size != sizeof(DDS_PIXELFORMAT))
{
return E_FAIL;
}
// Check for DX10 extension
bool bDXT10Header = false;
if ((hdr->ddspf.flags & DDS_FOURCC) &&
(MAKEFOURCC('D', 'X', '1', '0') == hdr->ddspf.fourCC))
{
// Must be long enough for both headers and magic value
if (fileInfo.EndOfFile.LowPart < (sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10)))
{
return E_FAIL;
}
bDXT10Header = true;
评论0