summaryrefslogtreecommitdiffstats
path: root/TextureLoader/src
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2015-10-21 04:05:29 +0000
committerEgor Yusov <egor.yusov@gmail.com>2015-10-21 04:05:29 +0000
commitf2e065dee10fb110e9d51175ee6381333319ef56 (patch)
treeda85ca78fe050280d7592bf6bf1071410846031f /TextureLoader/src
downloadDiligentTools-f2e065dee10fb110e9d51175ee6381333319ef56.tar.gz
DiligentTools-f2e065dee10fb110e9d51175ee6381333319ef56.zip
Release v1.0.0
Diffstat (limited to 'TextureLoader/src')
-rw-r--r--TextureLoader/src/DDSLoader.cpp1489
-rw-r--r--TextureLoader/src/Image.cpp409
-rw-r--r--TextureLoader/src/TextureLoader.cpp248
-rw-r--r--TextureLoader/src/TextureUtilities.cpp95
-rw-r--r--TextureLoader/src/pch.cpp25
5 files changed, 2266 insertions, 0 deletions
diff --git a/TextureLoader/src/DDSLoader.cpp b/TextureLoader/src/DDSLoader.cpp
new file mode 100644
index 0000000..2c701f3
--- /dev/null
+++ b/TextureLoader/src/DDSLoader.cpp
@@ -0,0 +1,1489 @@
+/* Copyright 2015 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+//--------------------------------------------------------------------------------------
+// File: DDSLoader.cpp
+//
+// Functions for loading a DDS texture and creating a Direct3D 11 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.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// http://go.microsoft.com/fwlink/?LinkId=248926
+// http://go.microsoft.com/fwlink/?LinkId=248929
+//--------------------------------------------------------------------------------------
+
+#include "pch.h"
+#include "dxgiformat.h"
+#include <memory>
+#include <algorithm>
+#include "DDSLoader.h"
+
+#ifndef _In_
+# define _In_
+#endif
+
+#ifndef _Out_
+# define _Out_
+#endif
+
+#ifndef _Out_opt_
+# define _Out_opt_
+#endif
+
+#ifndef _Outptr_opt_
+# define _Outptr_opt_
+#endif
+
+using namespace Diligent;
+using namespace Diligent;
+
+// D3D11 definitions
+
+enum D3D11_RESOURCE_DIMENSION
+{
+ D3D11_RESOURCE_DIMENSION_UNKNOWN = 0,
+ D3D11_RESOURCE_DIMENSION_BUFFER = 1,
+ D3D11_RESOURCE_DIMENSION_TEXTURE1D = 2,
+ D3D11_RESOURCE_DIMENSION_TEXTURE2D = 3,
+ D3D11_RESOURCE_DIMENSION_TEXTURE3D = 4
+};
+
+enum D3D11_RESOURCE_MISC_FLAG
+{
+ D3D11_RESOURCE_MISC_TEXTURECUBE = 0x4L,
+};
+
+#ifndef D3D11_REQ_MIP_LEVELS
+# define D3D11_REQ_MIP_LEVELS ( 15 )
+#endif
+
+#ifndef D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION
+# define D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION ( 2048 )
+#endif
+
+#ifndef D3D11_REQ_TEXTURE1D_U_DIMENSION
+# define D3D11_REQ_TEXTURE1D_U_DIMENSION ( 16384 )
+#endif
+
+#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION
+# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION ( 2048 )
+#endif
+
+#ifndef D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION
+# define D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION ( 16384 )
+#endif
+
+#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
+# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION ( 2048 )
+#endif
+
+#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION
+# define D3D11_REQ_TEXTURECUBE_DIMENSION ( 16384 )
+#endif
+
+
+//--------------------------------------------------------------------------------------
+// Macros
+//--------------------------------------------------------------------------------------
+#ifndef MAKEFOURCC
+ #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
+ ((Uint32)(Uint8)(ch0) | ((Uint32)(Uint8)(ch1) << 8) | \
+ ((Uint32)(Uint8)(ch2) << 16) | ((Uint32)(Uint8)(ch3) << 24))
+#endif /* defined(MAKEFOURCC) */
+
+//--------------------------------------------------------------------------------------
+// DDS file structure definitions
+//
+// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
+//--------------------------------------------------------------------------------------
+#pragma pack(push, 1)
+
+#define DDS_MAGIC 0x20534444 // "DDS "
+
+struct DDS_PIXELFORMAT
+{
+ Uint32 size;
+ Uint32 flags;
+ Uint32 fourCC;
+ Uint32 RGBBitCount;
+ Uint32 RBitMask;
+ Uint32 GBitMask;
+ Uint32 BBitMask;
+ Uint32 ABitMask;
+};
+
+#define DDS_FOURCC 0x00000004 // DDPF_FOURCC
+#define DDS_RGB 0x00000040 // DDPF_RGB
+#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS
+#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE
+#define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
+#define DDS_ALPHA 0x00000002 // DDPF_ALPHA
+#define DDS_PAL8 0x00000020 // DDPF_PALETTEINDEXED8
+
+#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
+#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT
+#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH
+#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH
+#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE
+
+#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
+#define DDS_WIDTH 0x00000004 // DDSD_WIDTH
+
+#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
+#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
+#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX
+
+#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
+
+#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME
+
+enum DDS_MISC_FLAGS2
+{
+ DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,
+};
+
+enum DDS_ALPHA_MODE
+{
+ DDS_ALPHA_MODE_UNKNOWN = 0,
+ DDS_ALPHA_MODE_STRAIGHT = 1,
+ DDS_ALPHA_MODE_PREMULTIPLIED = 2,
+ DDS_ALPHA_MODE_OPAQUE = 3,
+ DDS_ALPHA_MODE_CUSTOM = 4,
+};
+
+typedef struct
+{
+ Uint32 size;
+ Uint32 flags;
+ Uint32 height;
+ Uint32 width;
+ Uint32 pitchOrLinearSize;
+ Uint32 depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags
+ Uint32 mipMapCount;
+ Uint32 reserved1[11];
+ DDS_PIXELFORMAT ddspf;
+ Uint32 caps;
+ Uint32 caps2;
+ Uint32 caps3;
+ Uint32 caps4;
+ Uint32 reserved2;
+} DDS_HEADER;
+
+
+typedef struct
+{
+ DXGI_FORMAT dxgiFormat;
+ Uint32 resourceDimension;
+ Uint32 miscFlag; // see D3D11_RESOURCE_MISC_FLAG
+ Uint32 arraySize;
+ Uint32 miscFlags2;
+} DDS_HEADER_DXT10;
+
+#pragma pack(pop)
+
+
+
+//--------------------------------------------------------------------------------------
+// Return the BPP for a particular format
+//--------------------------------------------------------------------------------------
+static size_t BitsPerPixel(_In_ DXGI_FORMAT fmt)
+{
+ switch (fmt)
+ {
+ case DXGI_FORMAT_R32G32B32A32_TYPELESS:
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ return 128;
+
+ case DXGI_FORMAT_R32G32B32_TYPELESS:
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ case DXGI_FORMAT_R32G32B32_UINT:
+ case DXGI_FORMAT_R32G32B32_SINT:
+ return 96;
+
+ case DXGI_FORMAT_R16G16B16A16_TYPELESS:
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ case DXGI_FORMAT_R16G16B16A16_UNORM:
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ case DXGI_FORMAT_R16G16B16A16_SNORM:
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ case DXGI_FORMAT_R32G32_TYPELESS:
+ case DXGI_FORMAT_R32G32_FLOAT:
+ case DXGI_FORMAT_R32G32_UINT:
+ case DXGI_FORMAT_R32G32_SINT:
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
+ return 64;
+
+ case DXGI_FORMAT_R10G10B10A2_TYPELESS:
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ case DXGI_FORMAT_R10G10B10A2_UINT:
+ case DXGI_FORMAT_R11G11B10_FLOAT:
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS:
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ case DXGI_FORMAT_R16G16_TYPELESS:
+ case DXGI_FORMAT_R16G16_FLOAT:
+ case DXGI_FORMAT_R16G16_UNORM:
+ case DXGI_FORMAT_R16G16_UINT:
+ case DXGI_FORMAT_R16G16_SNORM:
+ case DXGI_FORMAT_R16G16_SINT:
+ case DXGI_FORMAT_R32_TYPELESS:
+ case DXGI_FORMAT_D32_FLOAT:
+ case DXGI_FORMAT_R32_FLOAT:
+ case DXGI_FORMAT_R32_UINT:
+ case DXGI_FORMAT_R32_SINT:
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
+ case DXGI_FORMAT_R8G8_B8G8_UNORM:
+ case DXGI_FORMAT_G8R8_G8B8_UNORM:
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
+ case DXGI_FORMAT_B8G8R8A8_TYPELESS:
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
+ case DXGI_FORMAT_B8G8R8X8_TYPELESS:
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
+ return 32;
+
+ case DXGI_FORMAT_R8G8_TYPELESS:
+ case DXGI_FORMAT_R8G8_UNORM:
+ case DXGI_FORMAT_R8G8_UINT:
+ case DXGI_FORMAT_R8G8_SNORM:
+ case DXGI_FORMAT_R8G8_SINT:
+ case DXGI_FORMAT_R16_TYPELESS:
+ case DXGI_FORMAT_R16_FLOAT:
+ case DXGI_FORMAT_D16_UNORM:
+ case DXGI_FORMAT_R16_UNORM:
+ case DXGI_FORMAT_R16_UINT:
+ case DXGI_FORMAT_R16_SNORM:
+ case DXGI_FORMAT_R16_SINT:
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ case DXGI_FORMAT_B4G4R4A4_UNORM:
+ return 16;
+
+ case DXGI_FORMAT_R8_TYPELESS:
+ case DXGI_FORMAT_R8_UNORM:
+ case DXGI_FORMAT_R8_UINT:
+ case DXGI_FORMAT_R8_SNORM:
+ case DXGI_FORMAT_R8_SINT:
+ case DXGI_FORMAT_A8_UNORM:
+ return 8;
+
+ case DXGI_FORMAT_R1_UNORM:
+ return 1;
+
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ case DXGI_FORMAT_BC4_SNORM:
+ return 4;
+
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ case DXGI_FORMAT_BC5_SNORM:
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ case DXGI_FORMAT_BC6H_SF16:
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ return 8;
+
+ default:
+ return 0;
+ }
+}
+
+
+static TEXTURE_FORMAT DXGIFormatToTexFormat( DXGI_FORMAT TexFormat )
+{
+ switch(TexFormat)
+ {
+ case DXGI_FORMAT_UNKNOWN: return TEX_FORMAT_UNKNOWN;
+
+ case DXGI_FORMAT_R32G32B32A32_TYPELESS: return TEX_FORMAT_RGBA32_TYPELESS;
+ case DXGI_FORMAT_R32G32B32A32_FLOAT: return TEX_FORMAT_RGBA32_FLOAT;
+ case DXGI_FORMAT_R32G32B32A32_UINT: return TEX_FORMAT_RGBA32_UINT;
+ case DXGI_FORMAT_R32G32B32A32_SINT: return TEX_FORMAT_RGBA32_SINT;
+
+ case DXGI_FORMAT_R32G32B32_TYPELESS: return TEX_FORMAT_RGB32_TYPELESS;
+ case DXGI_FORMAT_R32G32B32_FLOAT: return TEX_FORMAT_RGB32_FLOAT;
+ case DXGI_FORMAT_R32G32B32_UINT: return TEX_FORMAT_RGB32_UINT;
+ case DXGI_FORMAT_R32G32B32_SINT: return TEX_FORMAT_RGB32_SINT;
+
+ case DXGI_FORMAT_R16G16B16A16_TYPELESS: return TEX_FORMAT_RGBA16_TYPELESS;
+ case DXGI_FORMAT_R16G16B16A16_FLOAT: return TEX_FORMAT_RGBA16_FLOAT;
+ case DXGI_FORMAT_R16G16B16A16_UNORM: return TEX_FORMAT_RGBA16_UNORM;
+ case DXGI_FORMAT_R16G16B16A16_UINT: return TEX_FORMAT_RGBA16_UINT;
+ case DXGI_FORMAT_R16G16B16A16_SNORM: return TEX_FORMAT_RGBA16_SNORM;
+ case DXGI_FORMAT_R16G16B16A16_SINT: return TEX_FORMAT_RGBA16_SINT;
+
+ case DXGI_FORMAT_R32G32_TYPELESS: return TEX_FORMAT_RG32_TYPELESS;
+ case DXGI_FORMAT_R32G32_FLOAT: return TEX_FORMAT_RG32_FLOAT;
+ case DXGI_FORMAT_R32G32_UINT: return TEX_FORMAT_RG32_UINT;
+ case DXGI_FORMAT_R32G32_SINT: return TEX_FORMAT_RG32_SINT;
+
+ case DXGI_FORMAT_R32G8X24_TYPELESS: return TEX_FORMAT_R32G8X24_TYPELESS;
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return TEX_FORMAT_D32_FLOAT_S8X24_UINT;
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: return TEX_FORMAT_R32_FLOAT_X8X24_TYPELESS;
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: return TEX_FORMAT_X32_TYPELESS_G8X24_UINT;
+
+ case DXGI_FORMAT_R10G10B10A2_TYPELESS: return TEX_FORMAT_RGB10A2_TYPELESS;
+ case DXGI_FORMAT_R10G10B10A2_UNORM: return TEX_FORMAT_RGB10A2_UNORM;
+ case DXGI_FORMAT_R10G10B10A2_UINT: return TEX_FORMAT_RGB10A2_UINT;
+
+ case DXGI_FORMAT_R11G11B10_FLOAT: return TEX_FORMAT_R11G11B10_FLOAT;
+
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS: return TEX_FORMAT_RGBA8_TYPELESS;
+ case DXGI_FORMAT_R8G8B8A8_UNORM: return TEX_FORMAT_RGBA8_UNORM;
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return TEX_FORMAT_RGBA8_UNORM_SRGB;
+ case DXGI_FORMAT_R8G8B8A8_UINT: return TEX_FORMAT_RGBA8_UINT;
+ case DXGI_FORMAT_R8G8B8A8_SNORM: return TEX_FORMAT_RGBA8_SNORM;
+ case DXGI_FORMAT_R8G8B8A8_SINT: return TEX_FORMAT_RGBA8_SINT;
+
+ case DXGI_FORMAT_R16G16_TYPELESS: return TEX_FORMAT_RG16_TYPELESS;
+ case DXGI_FORMAT_R16G16_FLOAT: return TEX_FORMAT_RG16_FLOAT;
+ case DXGI_FORMAT_R16G16_UNORM: return TEX_FORMAT_RG16_UNORM;
+ case DXGI_FORMAT_R16G16_UINT: return TEX_FORMAT_RG16_UINT;
+ case DXGI_FORMAT_R16G16_SNORM: return TEX_FORMAT_RG16_SNORM;
+ case DXGI_FORMAT_R16G16_SINT: return TEX_FORMAT_RG16_SINT;
+
+ case DXGI_FORMAT_R32_TYPELESS: return TEX_FORMAT_R32_TYPELESS;
+ case DXGI_FORMAT_D32_FLOAT: return TEX_FORMAT_D32_FLOAT;
+ case DXGI_FORMAT_R32_FLOAT: return TEX_FORMAT_R32_FLOAT;
+ case DXGI_FORMAT_R32_UINT: return TEX_FORMAT_R32_UINT;
+ case DXGI_FORMAT_R32_SINT: return TEX_FORMAT_R32_SINT;
+
+ case DXGI_FORMAT_R24G8_TYPELESS: return TEX_FORMAT_R24G8_TYPELESS;
+ case DXGI_FORMAT_D24_UNORM_S8_UINT: return TEX_FORMAT_D24_UNORM_S8_UINT;
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return TEX_FORMAT_R24_UNORM_X8_TYPELESS;
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT: return TEX_FORMAT_X24_TYPELESS_G8_UINT;
+
+ case DXGI_FORMAT_R8G8_TYPELESS: return TEX_FORMAT_RG8_TYPELESS;
+ case DXGI_FORMAT_R8G8_UNORM: return TEX_FORMAT_RG8_UNORM;
+ case DXGI_FORMAT_R8G8_UINT: return TEX_FORMAT_RG8_UINT;
+ case DXGI_FORMAT_R8G8_SNORM: return TEX_FORMAT_RG8_SNORM;
+ case DXGI_FORMAT_R8G8_SINT: return TEX_FORMAT_RG8_SINT;
+
+ case DXGI_FORMAT_R16_TYPELESS: return TEX_FORMAT_R16_TYPELESS;
+ case DXGI_FORMAT_R16_FLOAT: return TEX_FORMAT_R16_FLOAT;
+ case DXGI_FORMAT_D16_UNORM: return TEX_FORMAT_D16_UNORM;
+ case DXGI_FORMAT_R16_UNORM: return TEX_FORMAT_R16_UNORM;
+ case DXGI_FORMAT_R16_UINT: return TEX_FORMAT_R16_UINT;
+ case DXGI_FORMAT_R16_SNORM: return TEX_FORMAT_R16_SNORM;
+ case DXGI_FORMAT_R16_SINT: return TEX_FORMAT_R16_SINT;
+
+ case DXGI_FORMAT_R8_TYPELESS: return TEX_FORMAT_R8_TYPELESS;
+ case DXGI_FORMAT_R8_UNORM: return TEX_FORMAT_R8_UNORM;
+ case DXGI_FORMAT_R8_UINT: return TEX_FORMAT_R8_UINT;
+ case DXGI_FORMAT_R8_SNORM: return TEX_FORMAT_R8_SNORM;
+ case DXGI_FORMAT_R8_SINT: return TEX_FORMAT_R8_SINT;
+ case DXGI_FORMAT_A8_UNORM: return TEX_FORMAT_A8_UNORM;
+
+ case DXGI_FORMAT_R1_UNORM : return TEX_FORMAT_R1_UNORM;
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: return TEX_FORMAT_RGB9E5_SHAREDEXP;
+ case DXGI_FORMAT_R8G8_B8G8_UNORM: return TEX_FORMAT_RG8_B8G8_UNORM;
+ case DXGI_FORMAT_G8R8_G8B8_UNORM: return TEX_FORMAT_G8R8_G8B8_UNORM;
+
+ case DXGI_FORMAT_BC1_TYPELESS: return TEX_FORMAT_BC1_TYPELESS;
+ case DXGI_FORMAT_BC1_UNORM: return TEX_FORMAT_BC1_UNORM;
+ case DXGI_FORMAT_BC1_UNORM_SRGB: return TEX_FORMAT_BC1_UNORM_SRGB;
+ case DXGI_FORMAT_BC2_TYPELESS: return TEX_FORMAT_BC2_TYPELESS;
+ case DXGI_FORMAT_BC2_UNORM: return TEX_FORMAT_BC2_UNORM;
+ case DXGI_FORMAT_BC2_UNORM_SRGB: return TEX_FORMAT_BC2_UNORM_SRGB;
+ case DXGI_FORMAT_BC3_TYPELESS: return TEX_FORMAT_BC3_TYPELESS;
+ case DXGI_FORMAT_BC3_UNORM: return TEX_FORMAT_BC3_UNORM;
+ case DXGI_FORMAT_BC3_UNORM_SRGB: return TEX_FORMAT_BC3_UNORM_SRGB;
+ case DXGI_FORMAT_BC4_TYPELESS: return TEX_FORMAT_BC4_TYPELESS;
+ case DXGI_FORMAT_BC4_UNORM: return TEX_FORMAT_BC4_UNORM;
+ case DXGI_FORMAT_BC4_SNORM: return TEX_FORMAT_BC4_SNORM;
+ case DXGI_FORMAT_BC5_TYPELESS: return TEX_FORMAT_BC5_TYPELESS;
+ case DXGI_FORMAT_BC5_UNORM: return TEX_FORMAT_BC5_UNORM;
+ case DXGI_FORMAT_BC5_SNORM: return TEX_FORMAT_BC5_SNORM;
+
+ case DXGI_FORMAT_B5G6R5_UNORM: return TEX_FORMAT_B5G6R5_UNORM;
+ case DXGI_FORMAT_B5G5R5A1_UNORM: return TEX_FORMAT_B5G5R5A1_UNORM;
+ case DXGI_FORMAT_B8G8R8A8_UNORM: return TEX_FORMAT_BGRA8_UNORM;
+ case DXGI_FORMAT_B8G8R8X8_UNORM: return TEX_FORMAT_BGRX8_UNORM;
+
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: return TEX_FORMAT_R10G10B10_XR_BIAS_A2_UNORM;
+
+ case DXGI_FORMAT_B8G8R8A8_TYPELESS: return TEX_FORMAT_BGRA8_TYPELESS;
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return TEX_FORMAT_BGRA8_UNORM_SRGB;
+ case DXGI_FORMAT_B8G8R8X8_TYPELESS: return TEX_FORMAT_BGRX8_TYPELESS;
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return TEX_FORMAT_BGRX8_UNORM_SRGB;
+
+ case DXGI_FORMAT_BC6H_TYPELESS: return TEX_FORMAT_BC6H_TYPELESS;
+ case DXGI_FORMAT_BC6H_UF16: return TEX_FORMAT_BC6H_UF16;
+ case DXGI_FORMAT_BC6H_SF16: return TEX_FORMAT_BC6H_SF16;
+ case DXGI_FORMAT_BC7_TYPELESS : return TEX_FORMAT_BC7_TYPELESS;
+ case DXGI_FORMAT_BC7_UNORM: return TEX_FORMAT_BC7_UNORM;
+ case DXGI_FORMAT_BC7_UNORM_SRGB: return TEX_FORMAT_BC7_UNORM_SRGB;
+
+ default: UNEXPECTED( "Unsupported DXGI formate" ); return TEX_FORMAT_UNKNOWN;
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Get surface information for a particular format
+//--------------------------------------------------------------------------------------
+static void GetSurfaceInfo(
+ _In_ size_t width,
+ _In_ size_t height,
+ _In_ DXGI_FORMAT fmt,
+ _Out_opt_ size_t* outNumBytes,
+ _Out_opt_ size_t* outRowBytes,
+ _Out_opt_ size_t* outNumRows
+ )
+{
+ size_t numBytes = 0;
+ size_t rowBytes = 0;
+ size_t numRows = 0;
+
+ bool bc = false;
+ bool packed = false;
+ size_t bcnumBytesPerBlock = 0;
+ switch (fmt)
+ {
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ case DXGI_FORMAT_BC4_SNORM:
+ bc = true;
+ bcnumBytesPerBlock = 8;
+ break;
+
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ case DXGI_FORMAT_BC5_SNORM:
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ case DXGI_FORMAT_BC6H_SF16:
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ bc = true;
+ bcnumBytesPerBlock = 16;
+ break;
+
+ case DXGI_FORMAT_R8G8_B8G8_UNORM:
+ case DXGI_FORMAT_G8R8_G8B8_UNORM:
+ packed = true;
+ break;
+ }
+
+ if (bc)
+ {
+ size_t numBlocksWide = 0;
+ if (width > 0)
+ {
+ numBlocksWide = std::max<size_t>(1, (width + 3) / 4);
+ }
+ size_t numBlocksHigh = 0;
+ if (height > 0)
+ {
+ numBlocksHigh = std::max<size_t>(1, (height + 3) / 4);
+ }
+ rowBytes = numBlocksWide * bcnumBytesPerBlock;
+ numRows = numBlocksHigh;
+ }
+ else if (packed)
+ {
+ rowBytes = ((width + 1) >> 1) * 4;
+ numRows = height;
+ }
+ else
+ {
+ size_t bpp = BitsPerPixel(fmt);
+ rowBytes = (width * bpp + 7) / 8; // round up to nearest byte
+ numRows = height;
+ }
+
+ numBytes = rowBytes * numRows;
+ if (outNumBytes)
+ {
+ *outNumBytes = numBytes;
+ }
+ if (outRowBytes)
+ {
+ *outRowBytes = rowBytes;
+ }
+ if (outNumRows)
+ {
+ *outNumRows = numRows;
+ }
+}
+
+
+//--------------------------------------------------------------------------------------
+#define ISBITMASK(r, g, b, a) (ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a)
+
+static DXGI_FORMAT GetDXGIFormat(const DDS_PIXELFORMAT& ddpf)
+{
+ if (ddpf.flags & DDS_RGB)
+ {
+ // Note that sRGB formats are written using the "DX10" extended header
+
+ switch (ddpf.RGBBitCount)
+ {
+ case 32:
+ if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
+ {
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+ }
+
+ if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))
+ {
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ }
+
+ if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))
+ {
+ return DXGI_FORMAT_B8G8R8X8_UNORM;
+ }
+
+ // No DXGI format maps to ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000) aka D3DFMT_X8B8G8R8
+
+ // Note that many common DDS reader/writers (including D3DX) swap the
+ // the RED/BLUE masks for 10:10:10:2 formats. We assumme
+ // below that the 'backwards' header mask is being used since it is most
+ // likely written by D3DX. The more robust solution is to use the 'DX10'
+ // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
+
+ // For 'correct' writers, this should be 0x000003ff, 0x000ffc00, 0x3ff00000 for RGB data
+ if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))
+ {
+ return DXGI_FORMAT_R10G10B10A2_UNORM;
+ }
+
+ // No DXGI format maps to ISBITMASK(0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000) aka D3DFMT_A2R10G10B10
+
+ if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
+ {
+ return DXGI_FORMAT_R16G16_UNORM;
+ }
+
+ if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000))
+ {
+ // Only 32-bit color channel format in D3D9 was R32F
+ return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114
+ }
+ break;
+
+ case 24:
+ // No 24bpp DXGI formats aka D3DFMT_R8G8B8
+ break;
+
+ case 16:
+ if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000))
+ {
+ return DXGI_FORMAT_B5G5R5A1_UNORM;
+ }
+ if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000))
+ {
+ return DXGI_FORMAT_B5G6R5_UNORM;
+ }
+
+ // No DXGI format maps to ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x0000) aka D3DFMT_X1R5G5B5
+ if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0xf000))
+ {
+ return DXGI_FORMAT_B4G4R4A4_UNORM;
+ }
+
+ // No DXGI format maps to ISBITMASK(0x0f00, 0x00f0, 0x000f, 0x0000) aka D3DFMT_X4R4G4B4
+
+ // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.
+ break;
+ }
+ }
+ else if (ddpf.flags & DDS_LUMINANCE)
+ {
+ if (8 == ddpf.RGBBitCount)
+ {
+ if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x00000000))
+ {
+ return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension
+ }
+
+ // No DXGI format maps to ISBITMASK(0x0f, 0x00, 0x00, 0xf0) aka D3DFMT_A4L4
+ }
+
+ if (16 == ddpf.RGBBitCount)
+ {
+ if (ISBITMASK(0x0000ffff, 0x00000000, 0x00000000, 0x00000000))
+ {
+ return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension
+ }
+ if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
+ {
+ return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension
+ }
+ }
+ }
+ else if (ddpf.flags & DDS_ALPHA)
+ {
+ if (8 == ddpf.RGBBitCount)
+ {
+ return DXGI_FORMAT_A8_UNORM;
+ }
+ }
+ else if (ddpf.flags & DDS_FOURCC)
+ {
+ if (MAKEFOURCC('D', 'X', 'T', '1') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC1_UNORM;
+ }
+ if (MAKEFOURCC('D', 'X', 'T', '3') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC2_UNORM;
+ }
+ if (MAKEFOURCC('D', 'X', 'T', '5') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC3_UNORM;
+ }
+
+ // While pre-mulitplied alpha isn't directly supported by the DXGI formats,
+ // they are basically the same as these BC formats so they can be mapped
+ if (MAKEFOURCC('D', 'X', 'T', '2') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC2_UNORM;
+ }
+ if (MAKEFOURCC('D', 'X', 'T', '4') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC3_UNORM;
+ }
+
+ if (MAKEFOURCC('A', 'T', 'I', '1') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC4_UNORM;
+ }
+ if (MAKEFOURCC('B', 'C', '4', 'U') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC4_UNORM;
+ }
+ if (MAKEFOURCC('B', 'C', '4', 'S') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC4_SNORM;
+ }
+
+ if (MAKEFOURCC('A', 'T', 'I', '2') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC5_UNORM;
+ }
+ if (MAKEFOURCC('B', 'C', '5', 'U') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC5_UNORM;
+ }
+ if (MAKEFOURCC('B', 'C', '5', 'S') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_BC5_SNORM;
+ }
+
+ // BC6H and BC7 are written using the "DX10" extended header
+
+ if (MAKEFOURCC('R', 'G', 'B', 'G') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_R8G8_B8G8_UNORM;
+ }
+ if (MAKEFOURCC('G', 'R', 'G', 'B') == ddpf.fourCC)
+ {
+ return DXGI_FORMAT_G8R8_G8B8_UNORM;
+ }
+
+ // Check for D3DFORMAT enums being set here
+ switch (ddpf.fourCC)
+ {
+ case 36: // D3DFMT_A16B16G16R16
+ return DXGI_FORMAT_R16G16B16A16_UNORM;
+
+ case 110: // D3DFMT_Q16W16V16U16
+ return DXGI_FORMAT_R16G16B16A16_SNORM;
+
+ case 111: // D3DFMT_R16F
+ return DXGI_FORMAT_R16_FLOAT;
+
+ case 112: // D3DFMT_G16R16F
+ return DXGI_FORMAT_R16G16_FLOAT;
+
+ case 113: // D3DFMT_A16B16G16R16F
+ return DXGI_FORMAT_R16G16B16A16_FLOAT;
+
+ case 114: // D3DFMT_R32F
+ return DXGI_FORMAT_R32_FLOAT;
+
+ case 115: // D3DFMT_G32R32F
+ return DXGI_FORMAT_R32G32_FLOAT;
+
+ case 116: // D3DFMT_A32B32G32R32F
+ return DXGI_FORMAT_R32G32B32A32_FLOAT;
+ }
+ }
+
+ return DXGI_FORMAT_UNKNOWN;
+}
+
+
+//--------------------------------------------------------------------------------------
+static DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+
+ case DXGI_FORMAT_BC1_UNORM:
+ return DXGI_FORMAT_BC1_UNORM_SRGB;
+
+ case DXGI_FORMAT_BC2_UNORM:
+ return DXGI_FORMAT_BC2_UNORM_SRGB;
+
+ case DXGI_FORMAT_BC3_UNORM:
+ return DXGI_FORMAT_BC3_UNORM_SRGB;
+
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
+
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
+
+ case DXGI_FORMAT_BC7_UNORM:
+ return DXGI_FORMAT_BC7_UNORM_SRGB;
+
+ default:
+ return format;
+ }
+}
+
+
+//--------------------------------------------------------------------------------------
+static void FillInitData(
+ _In_ size_t width,
+ _In_ size_t height,
+ _In_ size_t depth,
+ _In_ size_t mipCount,
+ _In_ size_t arraySize,
+ _In_ DXGI_FORMAT format,
+ _In_ size_t maxsize,
+ _In_ size_t bitSize,
+ _In_ const Uint8* bitData,
+ _Out_ size_t& twidth,
+ _Out_ size_t& theight,
+ _Out_ size_t& tdepth,
+ _Out_ size_t& skipMip,
+ _Out_ TextureSubResData *initData
+ )
+{
+ if (!bitData || !initData)
+ {
+ LOG_ERROR_AND_THROW( "Invalid arguments" );
+ }
+
+ skipMip = 0;
+ twidth = 0;
+ theight = 0;
+ tdepth = 0;
+
+ size_t NumBytes = 0;
+ size_t RowBytes = 0;
+ size_t NumRows = 0;
+ const Uint8* pSrcBits = bitData;
+ const Uint8* pEndBits = bitData + bitSize;
+
+ size_t index = 0;
+ for (size_t j = 0; j < arraySize; j++)
+ {
+ size_t w = width;
+ size_t h = height;
+ size_t d = depth;
+ for (size_t i = 0; i < mipCount; i++)
+ {
+ GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, &NumRows);
+
+ if ((mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize))
+ {
+ if (!twidth)
+ {
+ twidth = w;
+ theight = h;
+ tdepth = d;
+ }
+
+ VERIFY_EXPR(index < mipCount * arraySize);
+ initData[index].pData = (const void*)pSrcBits;
+ initData[index].Stride = static_cast<Uint32>(RowBytes);
+ initData[index].DepthStride = static_cast<Uint32>(NumBytes);
+ ++index;
+ }
+ else if (!j)
+ {
+ // Count number of skipped mipmaps (first item only)
+ ++skipMip;
+ }
+
+ if (pSrcBits + (NumBytes*d) > pEndBits)
+ {
+ LOG_ERROR_AND_THROW( "Out of bounds" );
+ }
+
+ pSrcBits += NumBytes * d;
+
+ w = w >> 1;
+ h = h >> 1;
+ d = d >> 1;
+ if (w == 0)
+ {
+ w = 1;
+ }
+ if (h == 0)
+ {
+ h = 1;
+ }
+ if (d == 0)
+ {
+ d = 1;
+ }
+ }
+ }
+
+ if (!index)
+ {
+ LOG_ERROR_AND_THROW( "Unknown error" );
+ }
+}
+
+
+//--------------------------------------------------------------------------------------
+static void CreateTexture(
+ _In_ IRenderDevice* pDevice,
+ _In_ Uint32 resDim,
+ _In_ size_t width,
+ _In_ size_t height,
+ _In_ size_t depth,
+ _In_ size_t mipCount,
+ _In_ size_t arraySize,
+ _In_ DXGI_FORMAT format,
+ _In_ USAGE usage,
+ _In_ unsigned int bindFlags,
+ _In_ unsigned int cpuAccessFlags,
+ _In_ unsigned int miscFlags,
+ _In_ bool forceSRGB,
+ _In_ bool isCubeMap,
+ _In_ TextureSubResData* initData,
+ _Outptr_opt_ ITexture** texture
+ )
+{
+ if (!pDevice || !initData)
+ {
+ LOG_ERROR_AND_THROW("Invalid arguments")
+ }
+
+
+ if (forceSRGB)
+ {
+ format = MakeSRGB(format);
+ }
+
+ TextureDesc desc;
+ desc.Width = static_cast<Uint32>(width);
+ desc.MipLevels = static_cast<Uint32>(mipCount);
+ desc.ArraySize = static_cast<Uint32>(arraySize);
+ desc.Format = DXGIFormatToTexFormat(format);
+ desc.Usage = usage;
+ desc.BindFlags = bindFlags;
+ desc.CPUAccessFlags = cpuAccessFlags;
+ //desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE;
+
+ TextureData InitData;
+ InitData.pSubResources = initData;
+ InitData.NumSubresources = static_cast<Uint32>(mipCount * arraySize);
+
+ switch (resDim)
+ {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+ {
+ desc.Type = arraySize > 1 ? TEXTURE_TYPE_1D_ARRAY : TEXTURE_TYPE_1D;
+ pDevice->CreateTexture( desc, InitData, texture );
+
+ // ID3D11Texture1D* tex = nullptr;
+ // hr = d3dDevice->CreateTexture1D(&desc, initData, &tex);
+
+ // if (SUCCEEDED(hr) && tex != 0)
+ // {
+ // if (textureView != 0)
+ // {
+ // D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
+ // memset(&SRVDesc, 0, sizeof(SRVDesc));
+ // SRVDesc.Format = format;
+
+ // if (arraySize > 1)
+ // {
+ // SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY;
+ // SRVDesc.Texture1DArray.MipLevels = desc.MipLevels;
+ // SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>(arraySize);
+ // }
+ // else
+ // {
+ // SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D;
+ // SRVDesc.Texture1D.MipLevels = desc.MipLevels;
+ // }
+
+ // hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
+
+ // if (FAILED(hr))
+ // {
+ // tex->Release();
+ // return hr;
+ // }
+ // }
+
+ // if (texture != 0)
+ // {
+ // *texture = tex;
+ // }
+ // else
+ // {
+ // tex->Release();
+ // }
+ // }
+ }
+ break;
+
+ case TEXTURE_TYPE_2D:
+ case TEXTURE_TYPE_2D_ARRAY:
+ case TEXTURE_TYPE_CUBE:
+ case TEXTURE_TYPE_CUBE_ARRAY:
+ {
+ desc.Type = isCubeMap ?
+ (arraySize > 1 ? TEXTURE_TYPE_CUBE_ARRAY : TEXTURE_TYPE_CUBE) :
+ (arraySize > 1 ? TEXTURE_TYPE_2D_ARRAY : TEXTURE_TYPE_2D);
+ desc.Height = static_cast<Uint32>(height);
+
+ //if (isCubeMap)
+ //{
+ // desc.MiscFlags = miscFlags | D3D11_RESOURCE_MISC_TEXTURECUBE;
+ //}
+ //else
+ //{
+ // desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE;
+ //}
+
+ pDevice->CreateTexture( desc, InitData, texture );
+
+ //ID3D11Texture2D* tex = nullptr;
+ //hr = d3dDevice->CreateTexture2D(&desc, initData, &tex);
+
+ //if (SUCCEEDED(hr) && tex != 0)
+ //{
+ // if (textureView != 0)
+ // {
+ // D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
+ // memset(&SRVDesc, 0, sizeof(SRVDesc));
+ // SRVDesc.Format = format;
+
+ // if (isCubeMap)
+ // {
+ // if (arraySize > 6)
+ // {
+ // SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
+ // SRVDesc.TextureCubeArray.MipLevels = desc.MipLevels;
+
+ // // Earlier we set arraySize to (NumCubes * 6)
+ // SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>(arraySize / 6);
+ // }
+ // else
+ // {
+ // SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE;
+ // SRVDesc.TextureCube.MipLevels = desc.MipLevels;
+ // }
+ // }
+ // else if (arraySize > 1)
+ // {
+ // SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY;
+ // SRVDesc.Texture2DArray.MipLevels = desc.MipLevels;
+ // SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>(arraySize);
+ // }
+ // else
+ // {
+ // SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D;
+ // SRVDesc.Texture2D.MipLevels = desc.MipLevels;
+ // }
+
+ // hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
+
+ // if (FAILED(hr))
+ // {
+ // tex->Release();
+ // return hr;
+ // }
+ // }
+
+ // if (texture != 0)
+ // {
+ // *texture = tex;
+ // }
+ // else
+ // {
+ // tex->Release();
+ // }
+ //}
+ }
+ break;
+
+ case TEXTURE_TYPE_3D:
+ {
+ desc.Type = TEXTURE_TYPE_3D;
+ desc.Height = static_cast<Uint32>(height);
+ desc.Depth = static_cast<Uint32>(depth);
+
+ //desc.MiscFlags = miscFlags & ~D3D11_RESOURCE_MISC_TEXTURECUBE;
+
+ pDevice->CreateTexture( desc, InitData, texture );
+
+ //ID3D11Texture3D* tex = nullptr;
+ //hr = d3dDevice->CreateTexture3D(&desc, 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 = D3D_SRV_DIMENSION_TEXTURE3D;
+ // SRVDesc.Texture3D.MipLevels = desc.MipLevels;
+
+ // hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
+
+ // if (FAILED(hr))
+ // {
+ // tex->Release();
+ // return hr;
+ // }
+ // }
+
+ // if (texture != 0)
+ // {
+ // *texture = tex;
+ // }
+ // else
+ // {
+ // tex->Release();
+ // }
+ //}
+ }
+ break;
+ }
+}
+
+//--------------------------------------------------------------------------------------
+static void CreateTextureFromDDS(
+ _In_ IRenderDevice* pDevice,
+ _In_ const DDS_HEADER* header,
+ _In_ const Uint8* bitData,
+ _In_ size_t bitSize,
+ _In_ size_t maxsize,
+ _In_ USAGE usage,
+ _In_ unsigned int bindFlags,
+ _In_ unsigned int cpuAccessFlags,
+ _In_ unsigned int miscFlags,
+ _In_ bool forceSRGB,
+ _Outptr_opt_ ITexture** texture
+ )
+{
+ size_t width = header->width;
+ size_t height = header->height;
+ size_t depth = header->depth;
+
+ Uint32 resDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
+ size_t arraySize = 1;
+ DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
+ bool isCubeMap = false;
+
+ size_t mipCount = header->mipMapCount;
+ if (0 == mipCount)
+ {
+ mipCount = 1;
+ }
+
+
+ if ((header->ddspf.flags & DDS_FOURCC) &&
+ (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))
+ {
+ auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>((const char*)header + sizeof(DDS_HEADER));
+
+ arraySize = d3d10ext->arraySize;
+ if (arraySize == 0)
+ {
+ LOG_ERROR_AND_THROW("Array size is zero");
+ }
+
+ if (BitsPerPixel(d3d10ext->dxgiFormat) == 0)
+ {
+ LOG_ERROR_AND_THROW("Undefined DXGI format");
+ }
+
+ format = d3d10ext->dxgiFormat;
+
+ switch (d3d10ext->resourceDimension)
+ {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+ // D3DX writes 1D textures with a fixed Height of 1
+ if ((header->flags & DDS_HEIGHT) && height != 1)
+ {
+ LOG_ERROR_AND_THROW("Unexpected height (", height, ") for texture 1D");
+ }
+ height = depth = 1;
+ break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
+ if (d3d10ext->miscFlag & D3D11_RESOURCE_MISC_TEXTURECUBE)
+ {
+ arraySize *= 6;
+ isCubeMap = true;
+ }
+ depth = 1;
+ break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
+ if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))
+ {
+ LOG_ERROR_AND_THROW("DDS_HEADER_FLAGS_VOLUME flag is not set");
+ }
+
+ if (arraySize > 1)
+ {
+ LOG_ERROR_AND_THROW("Texture3D arrays are not allowed");
+ }
+ break;
+
+ default:
+ LOG_ERROR_AND_THROW("Unknown resource dimension");
+ }
+
+ resDim = d3d10ext->resourceDimension;
+ }
+ else
+ {
+ format = GetDXGIFormat(header->ddspf);
+
+ if (format == DXGI_FORMAT_UNKNOWN)
+ {
+ LOG_ERROR_AND_THROW("Unknown DXGIF format");
+ }
+
+ if (header->flags & DDS_HEADER_FLAGS_VOLUME)
+ {
+ resDim = D3D11_RESOURCE_DIMENSION_TEXTURE3D;
+ }
+ else
+ {
+ if (header->caps2 & DDS_CUBEMAP)
+ {
+ // We require all six faces to be defined
+ if ((header->caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)
+ {
+ LOG_ERROR_AND_THROW("All six faces of a cubemap must be defined");
+ }
+
+ arraySize = 6;
+ isCubeMap = true;
+ }
+
+ depth = 1;
+ resDim = D3D11_RESOURCE_DIMENSION_TEXTURE2D;
+
+ // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
+ }
+
+ VERIFY_EXPR(BitsPerPixel(format) != 0);
+ }
+
+ // Bound sizes (for security purposes we don't trust DDS file metadata larger than the D3D 11.x hardware requirements)
+ if (mipCount > D3D11_REQ_MIP_LEVELS)
+ {
+ LOG_ERROR_AND_THROW("Too many mip levels specified");
+ }
+
+ switch (resDim)
+ {
+ case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
+ if ((arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||
+ (width > D3D11_REQ_TEXTURE1D_U_DIMENSION))
+ {
+ LOG_ERROR_AND_THROW("Texture1D dimensions are out of bounds");
+ }
+ break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
+ if (isCubeMap)
+ {
+ // This is the right bound because we set arraySize to (NumCubes*6) above
+ if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
+ (width > D3D11_REQ_TEXTURECUBE_DIMENSION) ||
+ (height > D3D11_REQ_TEXTURECUBE_DIMENSION))
+ {
+ LOG_ERROR_AND_THROW("TextureCube dimensions are out of bounds");
+ }
+ }
+ else if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
+ (width > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||
+ (height > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION))
+ {
+ LOG_ERROR_AND_THROW("Texture2D dimensions are out of bounds");
+ }
+ break;
+
+ case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
+ if ((arraySize > 1) ||
+ (width > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
+ (height > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
+ (depth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))
+ {
+ LOG_ERROR_AND_THROW("Texture3D dimensions are out of bounds");
+ }
+ break;
+ }
+ // Create the texture
+ std::unique_ptr<TextureSubResData[]> initData(new TextureSubResData[mipCount * arraySize]);
+
+ size_t skipMip = 0;
+ size_t twidth = 0;
+ size_t theight = 0;
+ size_t tdepth = 0;
+ FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, twidth, theight, tdepth, skipMip, initData.get());
+
+ CreateTexture(pDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, format, usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB, isCubeMap, initData.get(), texture/*, textureView*/);
+
+#if 0
+ if (FAILED(hr) && !maxsize && (mipCount > 1))
+ {
+ // Retry with a maxsize determined by feature level
+ switch (d3dDevice->GetFeatureLevel())
+ {
+ case D3D_FEATURE_LEVEL_9_1:
+ case D3D_FEATURE_LEVEL_9_2:
+ if (isCubeMap)
+ {
+ maxsize = D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION;
+ }
+ else
+ {
+ maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
+ ? D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
+ : D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ }
+ break;
+
+ case D3D_FEATURE_LEVEL_9_3:
+ maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
+ ? D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
+ : D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ break;
+
+ default: // D3D_FEATURE_LEVEL_10_0 & D3D_FEATURE_LEVEL_10_1
+ maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
+ ? D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
+ : D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ break;
+ }
+
+ FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, twidth, theight, tdepth, skipMip, initData.get());
+
+ hr = CreateTexture(d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, format, usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB, isCubeMap, initData.get(), texture, textureView);
+ }
+#endif
+}
+
+#if 0
+//--------------------------------------------------------------------------------------
+static D2D1_ALPHA_MODE GetAlphaMode(_In_ const DDS_HEADER* header)
+{
+ if (header->ddspf.flags & DDS_FOURCC)
+ {
+ if (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC)
+ {
+ auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>((const char*)header + sizeof(DDS_HEADER));
+ switch (d3d10ext->miscFlags2 & DDS_MISC_FLAGS2_ALPHA_MODE_MASK)
+ {
+ case DDS_ALPHA_MODE_STRAIGHT:
+ return D2D1_ALPHA_MODE_STRAIGHT;
+
+ case DDS_ALPHA_MODE_PREMULTIPLIED:
+ return D2D1_ALPHA_MODE_PREMULTIPLIED;
+
+ case DDS_ALPHA_MODE_OPAQUE:
+ case DDS_ALPHA_MODE_CUSTOM:
+ // No D2D1_ALPHA_MODE equivalent, so return "Ignore" for now
+ return D2D1_ALPHA_MODE_IGNORE;
+ }
+ }
+ else if ((MAKEFOURCC('D', 'X', 'T', '2') == header->ddspf.fourCC)
+ || (MAKEFOURCC('D', 'X', 'T', '4') == header->ddspf.fourCC))
+ {
+ return D2D1_ALPHA_MODE_PREMULTIPLIED;
+ }
+ // DXT1, DXT3, and DXT5 legacy files could be straight alpha or something else, so return "Unknown" to leave it up to the app
+ }
+
+ return D2D1_ALPHA_MODE_UNKNOWN;
+}
+
+#endif
+
+//--------------------------------------------------------------------------------------
+void CreateDDSTextureFromMemory(
+ IRenderDevice* pDevice,
+ const Uint8* ddsData,
+ size_t ddsDataSize,
+ ITexture** texture,
+ size_t maxsize/*,
+ D2D1_ALPHA_MODE* alphaMode*/
+ )
+{
+ return CreateDDSTextureFromMemoryEx(pDevice, ddsData, ddsDataSize, maxsize, USAGE_DEFAULT, BIND_SHADER_RESOURCE, 0, 0, false, texture/*, alphaMode*/);
+}
+
+
+//--------------------------------------------------------------------------------------
+void CreateDDSTextureFromMemoryEx(
+ IRenderDevice* pDevice,
+ const Uint8* ddsData,
+ size_t ddsDataSize,
+ size_t maxsize,
+ USAGE usage,
+ unsigned int bindFlags,
+ unsigned int cpuAccessFlags,
+ unsigned int miscFlags,
+ bool forceSRGB,
+ ITexture** texture/*,
+ D2D1_ALPHA_MODE* alphaMode*/
+ )
+{
+ if (texture)
+ {
+ VERIFY( *texture == nullptr, "Overwriting reference to an existing object is unsafe")
+ *texture = nullptr;
+ }
+ //if (textureView)
+ //{
+ // *textureView = nullptr;
+ //}
+ //if (alphaMode)
+ //{
+ // *alphaMode = D2D1_ALPHA_MODE_UNKNOWN;
+ //}
+
+ if (!pDevice || !ddsData || (!texture /*&& !textureView*/))
+ {
+ LOG_ERROR_AND_THROW("Invalid arguments");
+ }
+
+ // Validate DDS file in memory
+ if (ddsDataSize < (sizeof(Uint32) + sizeof(DDS_HEADER)))
+ {
+ LOG_ERROR_AND_THROW("Invalid dds file");
+ }
+
+ Uint32 dwMagicNumber = *(const Uint32*)(ddsData);
+ if (dwMagicNumber != DDS_MAGIC)
+ {
+ LOG_ERROR_AND_THROW("Invalid dds file");
+ }
+
+ auto header = reinterpret_cast<const DDS_HEADER*>(ddsData + sizeof(Uint32));
+
+ // Verify header to validate DDS file
+ if (header->size != sizeof(DDS_HEADER) ||
+ header->ddspf.size != sizeof(DDS_PIXELFORMAT))
+ {
+ LOG_ERROR_AND_THROW("Invalid dds file header");
+ }
+
+ // Check for DX10 extension
+ bool bDXT10Header = false;
+ if ((header->ddspf.flags & DDS_FOURCC) &&
+ (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))
+ {
+ // Must be long enough for both headers and magic value
+ if (ddsDataSize < (sizeof(DDS_HEADER) + sizeof(Uint32) + sizeof(DDS_HEADER_DXT10)))
+ {
+ LOG_ERROR_AND_THROW("Invalid DX10 extension");
+ }
+
+ bDXT10Header = true;
+ }
+
+ ptrdiff_t offset = sizeof(Uint32) + sizeof(DDS_HEADER) + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0);
+
+ CreateTextureFromDDS(pDevice, header, ddsData + offset, ddsDataSize - offset, maxsize, usage, bindFlags, cpuAccessFlags, miscFlags, forceSRGB, texture/*, textureView*/);
+
+ //if (alphaMode)
+ // *alphaMode = GetAlphaMode(header);
+}
diff --git a/TextureLoader/src/Image.cpp b/TextureLoader/src/Image.cpp
new file mode 100644
index 0000000..d78f2da
--- /dev/null
+++ b/TextureLoader/src/Image.cpp
@@ -0,0 +1,409 @@
+/* Copyright 2015 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "Image.h"
+#include "Errors.h"
+
+#include "tiffio.h"
+#include "png.h"
+#include "jpeglib.h"
+
+#include "DataBlobImpl.h"
+#include "DebugUtilities.h"
+#include "RefCntAutoPtr.h"
+
+using namespace Diligent;
+using namespace Diligent;
+
+namespace Diligent
+{
+ class TIFFClientOpenWrapper
+ {
+ public:
+ TIFFClientOpenWrapper( IDataBlob *pData ) :
+ m_pData( pData ),
+ m_Offset( 0 ),
+ m_Size( pData->GetSize() )
+ {
+ }
+
+ static tmsize_t TIFFReadProc( thandle_t pClientData, void* pBuffer, tmsize_t Size )
+ {
+ auto *pThis = reinterpret_cast<TIFFClientOpenWrapper*>(pClientData);
+ auto *pSrcPtr = reinterpret_cast<Uint8*>(pThis->m_pData->GetDataPtr()) + pThis->m_Offset;
+ memcpy( pBuffer, pSrcPtr, Size );
+ pThis->m_Offset += Size;
+ return Size;
+ }
+
+ static tmsize_t TIFFWriteProc( thandle_t pClientData, void* pBuffer, tmsize_t Size )
+ {
+ auto *pThis = reinterpret_cast<TIFFClientOpenWrapper*>(pClientData);
+ if( pThis->m_Offset + Size > pThis->m_Size )
+ {
+ pThis->m_Size = pThis->m_Offset + Size;
+ pThis->m_pData->Resize( pThis->m_Size );
+ }
+ auto *pDstPtr = reinterpret_cast<Uint8*>(pThis->m_pData->GetDataPtr()) + pThis->m_Offset;
+ memcpy( pDstPtr, pBuffer, Size );
+ pThis->m_Offset += Size;
+ return Size;
+ }
+
+ static toff_t TIFFSeekProc( thandle_t pClientData, toff_t Offset, int Whence )
+ {
+ auto *pThis = reinterpret_cast<TIFFClientOpenWrapper*>(pClientData);
+ switch( Whence )
+ {
+ case SEEK_SET: pThis->m_Offset = static_cast<size_t>(Offset); break;
+ case SEEK_CUR: pThis->m_Offset += static_cast<size_t>(Offset); break;
+ case SEEK_END: pThis->m_Offset = pThis->m_Size + static_cast<size_t>(Offset); break;
+ default: UNEXPECTED( "Unexpected whence" );
+ }
+
+ return pThis->m_Offset;
+ }
+
+ static int TIFFCloseProc( thandle_t pClientData )
+ {
+ auto *pThis = reinterpret_cast<TIFFClientOpenWrapper*>(pClientData);
+ pThis->m_pData.Release();
+ pThis->m_Size = 0;
+ pThis->m_Offset = 0;
+ return 0;
+ }
+
+ static toff_t TIFFSizeProc( thandle_t pClientData )
+ {
+ auto *pThis = reinterpret_cast<TIFFClientOpenWrapper*>(pClientData);
+ return pThis->m_Size;
+ }
+
+ static int TIFFMapFileProc( thandle_t pClientData, void** base, toff_t* size )
+ {
+ UNEXPECTED( "Client file mapping is not implemented. Use \'m\' when opening TIFF file to disable file mapping." )
+ return 0;
+ }
+
+ static void TIFFUnmapFileProc( thandle_t pClientData, void* base, toff_t size )
+ {
+ UNEXPECTED( "Client file mapping is not implemented. Use \'m\' when opening TIFF file to disable file mapping." )
+ }
+
+ private:
+ size_t m_Offset;
+ size_t m_Size;
+ RefCntAutoPtr<IDataBlob> m_pData;
+ };
+
+ void Image::LoadTiffFile( IDataBlob *pFileData, const ImageLoadInfo& LoadInfo )
+ {
+ TIFFClientOpenWrapper TiffClientOpenWrpr(pFileData);
+
+ auto TiffFile = TIFFClientOpen("", "rm", &TiffClientOpenWrpr,
+ TIFFClientOpenWrapper::TIFFReadProc,
+ TIFFClientOpenWrapper::TIFFWriteProc,
+ TIFFClientOpenWrapper::TIFFSeekProc,
+ TIFFClientOpenWrapper::TIFFCloseProc,
+ TIFFClientOpenWrapper::TIFFSizeProc,
+ TIFFClientOpenWrapper::TIFFMapFileProc,
+ TIFFClientOpenWrapper::TIFFUnmapFileProc);
+
+ TIFFGetField(TiffFile, TIFFTAG_IMAGEWIDTH, &m_Desc.Width);
+ TIFFGetField(TiffFile, TIFFTAG_IMAGELENGTH, &m_Desc.Height);
+
+ Uint16 SamplesPerPixel = 0;
+ // SamplesPerPixel is usually 1 for bilevel, grayscale, and palette-color images.
+ // SamplesPerPixel is usually 3 for RGB images. If this value is higher, ExtraSamples
+ // should give an indication of the meaning of the additional channels.
+ TIFFGetField(TiffFile, TIFFTAG_SAMPLESPERPIXEL, &SamplesPerPixel);
+ m_Desc.NumComponents = SamplesPerPixel;
+
+ Uint16 BitsPerSample = 0;
+ TIFFGetField(TiffFile, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
+ m_Desc.BitsPerPixel = m_Desc.NumComponents * BitsPerSample;
+
+ auto ScanlineSize = TIFFScanlineSize(TiffFile);
+ m_Desc.RowStride = static_cast<Uint32>( ScanlineSize );
+ m_pData->Resize(m_Desc.Height * m_Desc.RowStride );
+ auto *pDataPtr = reinterpret_cast<Uint8*>( m_pData->GetDataPtr() );
+ for (Uint32 row = 0; row < m_Desc.Height; row++, pDataPtr += ScanlineSize)
+ {
+ TIFFReadScanline(TiffFile, pDataPtr, row);
+ }
+ TIFFClose(TiffFile);
+ }
+
+
+ class PNGReadFnHelper
+ {
+ public:
+ PNGReadFnHelper( IDataBlob *pData ) :
+ m_pData( pData ),
+ m_Offset( 0 )
+ {
+ }
+
+ static void ReadData( png_structp pngPtr, png_bytep data, png_size_t length )
+ {
+ auto pThis = reinterpret_cast<PNGReadFnHelper*>( png_get_io_ptr(pngPtr) );
+ memcpy( data, reinterpret_cast<Uint8*>(pThis->m_pData->GetDataPtr()) + pThis->m_Offset, length );
+ pThis->m_Offset += length;
+ }
+
+ private:
+ RefCntAutoPtr<IDataBlob> m_pData;
+ size_t m_Offset;
+ };
+
+ void Image::LoadPngFile( IDataBlob *pFileData, const ImageLoadInfo& LoadInfo )
+ {
+ // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/
+ // http://www.libpng.org/pub/png/book/chapter13.html#png.ch13.div.10
+ // https://gist.github.com/niw/5963798\
+
+ PNGReadFnHelper ReadFnHelper(pFileData);
+
+ const size_t PngSigSize = 8;
+ png_const_bytep pngsig = reinterpret_cast<png_const_bytep>(pFileData->GetDataPtr());
+ //Let LibPNG check the signature. If this function returns 0, everything is OK.
+ if( png_sig_cmp( pngsig, 0, PngSigSize ) != 0 )
+ {
+ LOG_ERROR_AND_THROW( "Invalid png signature" );
+ }
+
+ png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ VERIFY(png, "png_create_read_struct() failed")
+
+ png_infop info = png_create_info_struct(png);
+ VERIFY(info, "png_create_info_struct() failed")
+
+ if( setjmp( png_jmpbuf( png ) ) )
+ {
+ // When an error occurs during parsing, libPNG will jump to here
+ png_destroy_read_struct(&png, &info, (png_infopp)0);
+ LOG_ERROR_AND_THROW( "Failed to read png file" );
+ }
+
+ png_set_read_fn(png, (png_voidp)&ReadFnHelper, PNGReadFnHelper::ReadData);
+
+ png_read_info(png, info);
+
+ m_Desc.Width = png_get_image_width(png, info);
+ m_Desc.Height = png_get_image_height(png, info);
+ m_Desc.NumComponents = png_get_channels(png, info);
+ auto bit_depth = png_get_bit_depth(png, info);
+ m_Desc.BitsPerPixel = bit_depth * m_Desc.NumComponents;
+ auto color_type = png_get_color_type(png, info);
+
+ // PNG files store 16-bit pixels in network byte order (big-endian, ie
+ // most significant bytes first). png_set_swap() shall switch the byte-order
+ // to little-endian (ie, least significant bits first).
+ if( bit_depth == 16 )
+ png_set_swap(png);
+
+#if 0
+ // Read any color_type into 8bit depth, RGBA format.
+ // See http://www.libpng.org/pub/png/libpng-manual.txt
+
+ if( bit_depth == 16 )
+ png_set_strip_16( png );
+
+ if( color_type == PNG_COLOR_TYPE_PALETTE )
+ png_set_palette_to_rgb( png );
+
+ // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
+ if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
+ png_set_expand_gray_1_2_4_to_8( png );
+
+ if( png_get_valid( png, info, PNG_INFO_tRNS ) )
+ png_set_tRNS_to_alpha( png );
+
+ // These color_type don't have an alpha channel then fill it with 0xff.
+ if( color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_PALETTE )
+ png_set_filler( png, 0xFF, PNG_FILLER_AFTER );
+
+ if( color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
+ png_set_gray_to_rgb( png );
+
+ png_read_update_info( png, info );
+#endif
+
+ //Array of row pointers. One for every row.
+ std::vector<png_bytep> rowPtrs(m_Desc.Height);
+
+ //Alocate a buffer with enough space.
+ m_Desc.RowStride = m_Desc.Width * bit_depth * m_Desc.NumComponents / 8;
+ m_pData->Resize( m_Desc.Height * m_Desc.RowStride );
+ for( size_t i = 0; i < m_Desc.Height; i++ )
+ rowPtrs[i] = reinterpret_cast<png_bytep>(m_pData->GetDataPtr()) + i * m_Desc.RowStride;
+
+ //Read the imagedata and write it to the adresses pointed to
+ //by rowptrs (in other words: our image databuffer)
+ png_read_image( png, rowPtrs.data() );
+
+ png_destroy_read_struct(&png, &info, (png_infopp)0);
+ }
+
+
+
+ struct my_jpeg_error_mgr {
+ jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;// for return to caller
+ };
+
+ // Here's the routine that will replace the standard error_exit method:
+ METHODDEF(void)
+ my_error_exit (j_common_ptr cinfo)
+ {
+ // cinfo->err really points to a my_jpeg_error_mgr struct, so coerce pointer
+ my_jpeg_error_mgr* myerr = (my_jpeg_error_mgr*) cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message) (cinfo);
+
+ // Return control to the setjmp point
+ longjmp(myerr->setjmp_buffer, 1);
+ }
+
+ void Image::LoadJpegFile( IDataBlob *pFileData, const ImageLoadInfo& LoadInfo )
+ {
+ // https://github.com/LuaDist/libjpeg/blob/master/example.c
+
+ // This struct contains the JPEG decompression parameters and pointers to
+ // working space (which is allocated as needed by the JPEG library).
+ jpeg_decompress_struct cinfo;
+
+ // We use our private extension JPEG error handler.
+ // Note that this struct must live as long as the main JPEG parameter
+ // struct, to avoid dangling-pointer problems.
+ my_jpeg_error_mgr jerr;
+
+ // Step 1: allocate and initialize JPEG decompression object
+
+ // We set up the normal JPEG error routines, then override error_exit.
+ cinfo.err = jpeg_std_error( &jerr.pub );
+ jerr.pub.error_exit = my_error_exit;
+ // Establish the setjmp return context for my_error_exit to use.
+ if( setjmp( jerr.setjmp_buffer ) )
+ {
+ // If we get here, the JPEG code has signaled an error.
+ // We need to clean up the JPEG object, close the input file, and return.
+ jpeg_destroy_decompress( &cinfo );
+ LOG_ERROR_AND_THROW( "Failed to decompress JPEG image" )
+ }
+ // Now we can initialize the JPEG decompression object.
+ jpeg_create_decompress( &cinfo );
+
+ // Step 2: specify data source
+ jpeg_mem_src( &cinfo, reinterpret_cast<unsigned char*>(pFileData->GetDataPtr()), static_cast<unsigned long>(pFileData->GetSize()) );
+
+ // Step 3: read file parameters with jpeg_read_header()
+ jpeg_read_header( &cinfo, TRUE );
+ // We can ignore the return value from jpeg_read_header since
+ // (a) suspension is not possible with the stdio data source, and
+ // (b) we passed TRUE to reject a tables-only JPEG file as an error.
+ // See libjpeg.txt for more info.
+
+
+ // Step 4: set parameters for decompression
+
+ // In this example, we don't need to change any of the defaults set by
+ // jpeg_read_header(), so we do nothing here.
+
+
+ // Step 5: Start decompressor
+
+ jpeg_start_decompress( &cinfo );
+ // We can ignore the return value since suspension is not possible
+ // with the stdio data source.
+
+ // We may need to do some setup of our own at this point before reading
+ // the data. After jpeg_start_decompress() we have the correct scaled
+ // output image dimensions available, as well as the output colormap
+ // if we asked for color quantization.
+
+ m_Desc.Width = cinfo.output_width;
+ m_Desc.Height = cinfo.output_height;
+ m_Desc.NumComponents = cinfo.output_components;
+ m_Desc.RowStride = m_Desc.Width * m_Desc.NumComponents;
+ m_Desc.BitsPerPixel = 8 * m_Desc.NumComponents;
+
+ m_pData->Resize(m_Desc.RowStride * m_Desc.Height);
+ // Step 6: while (scan lines remain to be read)
+ // jpeg_read_scanlines(...);
+
+ // Here we use the library's state variable cinfo.output_scanline as the
+ // loop counter, so that we don't have to keep track ourselves.
+ while( cinfo.output_scanline < cinfo.output_height ) {
+ // jpeg_read_scanlines expects an array of pointers to scanlines.
+ // Here the array is only one element long, but you could ask for
+ // more than one scanline at a time if that's more convenient.
+
+
+ auto *pDstScanline = reinterpret_cast<Uint8*>( m_pData->GetDataPtr() ) + cinfo.output_scanline * m_Desc.RowStride;
+ JSAMPROW RowPtrs[] = { reinterpret_cast<JSAMPROW>(pDstScanline) };
+ jpeg_read_scanlines( &cinfo, RowPtrs, 1 );
+ }
+
+ // Step 7: Finish decompression
+
+ jpeg_finish_decompress( &cinfo );
+ // We can ignore the return value since suspension is not possible
+ // with the stdio data source.
+
+ // Step 8: Release JPEG decompression object
+
+ // This is an important step since it will release a good deal of memory.
+ jpeg_destroy_decompress( &cinfo );
+
+ // At this point you may want to check to see whether any corrupt-data
+ // warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+ }
+
+ Image::Image( Diligent::IFileStream *pSrcFile,
+ const ImageLoadInfo& LoadInfo ) :
+ m_pData( new Diligent::DataBlobImpl )
+ {
+ RefCntAutoPtr<IDataBlob> pFileData( new Diligent::DataBlobImpl );
+ pSrcFile->Read(pFileData);
+
+ if( LoadInfo.Format == EImageFileFormat::tiff )
+ {
+ LoadTiffFile(pFileData, LoadInfo );
+ }
+ else if( LoadInfo.Format == EImageFileFormat::png )
+ {
+ LoadPngFile(pFileData, LoadInfo );
+ }
+ else if( LoadInfo.Format == EImageFileFormat::jpeg )
+ {
+ LoadJpegFile(pFileData, LoadInfo );
+ }
+ }
+}
diff --git a/TextureLoader/src/TextureLoader.cpp b/TextureLoader/src/TextureLoader.cpp
new file mode 100644
index 0000000..63134a4
--- /dev/null
+++ b/TextureLoader/src/TextureLoader.cpp
@@ -0,0 +1,248 @@
+/* Copyright 2015 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "TextureLoader.h"
+#include "GraphicsUtilities.h"
+#include <algorithm>
+#include <limits>
+#include "DDSLoader.h"
+
+using namespace Diligent;
+
+namespace Diligent
+{
+ static const float a = 0.055f;
+
+ // https://en.wikipedia.org/wiki/SRGB
+ float SRGBToLinear(float SRGB)
+ {
+ if( SRGB < 0.04045f )
+ return SRGB / 12.92f;
+ else
+ return powf( (SRGB + a) / (1 + a), 2.4f );
+ }
+
+ float LinearToSRGB( float c )
+ {
+ if( c < 0.0031308f )
+ return 12.92f * c;
+ else
+ return (1+a) * pow(c, 1.f/2.4f) - a;
+ }
+
+ template<typename ChannelType>
+ ChannelType SRGBAverage(ChannelType c0, ChannelType c1, ChannelType c2, ChannelType c3)
+ {
+ const float NormVal = static_cast<float>(std::numeric_limits<ChannelType>::max());
+ float fc0 = static_cast<float>(c0) / NormVal;
+ float fc1 = static_cast<float>(c1) / NormVal;
+ float fc2 = static_cast<float>(c2) / NormVal;
+ float fc3 = static_cast<float>(c3) / NormVal;
+
+ float fLinearAverage = (SRGBToLinear( fc0 ) + SRGBToLinear( fc1 ) + SRGBToLinear( fc2 ) + SRGBToLinear( fc3 )) / 4.f;
+ float fSRGBAverage = LinearToSRGB(fLinearAverage);
+ Int32 SRGBAverage = static_cast<Int32>(fSRGBAverage * NormVal);
+ SRGBAverage = std::min(SRGBAverage, static_cast<Int32>( std::numeric_limits<ChannelType>::max()) );
+ SRGBAverage = std::max(SRGBAverage, static_cast<Int32>( std::numeric_limits<ChannelType>::min()) );
+ return static_cast<ChannelType>(SRGBAverage);
+ }
+
+ template < typename ChannelType >
+ void ComputeCoarseMip(Uint32 NumChannels, bool IsSRGB,
+ const void *pFineMip, Uint32 FineMipStride,
+ void *pCoarseMip, Uint32 CoarseMipStride,
+ Uint32 CoarseMipWidth, Uint32 CoarseMipHeight)
+ {
+ for( Uint32 row = 0; row < CoarseMipHeight; ++row )
+ for( Uint32 col = 0; col < CoarseMipWidth; ++col )
+ {
+ auto FineRow0 = reinterpret_cast<const ChannelType*>( reinterpret_cast<const Uint8*>(pFineMip) + row * 2 * FineMipStride );
+ auto FineRow1 = reinterpret_cast<const ChannelType*>( reinterpret_cast<const Uint8*>(pFineMip) + (row * 2 + 1 ) * FineMipStride );
+
+ for( Uint32 c = 0; c < NumChannels; ++c )
+ {
+ auto Col00 = FineRow0[ col*2 * NumChannels + c ];
+ auto Col01 = FineRow0[ (col*2+1) * NumChannels + c ];
+ auto Col10 = FineRow1[ col*2 * NumChannels + c ];
+ auto Col11 = FineRow1[ (col*2+1) * NumChannels + c ];
+ auto &DstCol = reinterpret_cast<ChannelType*>(reinterpret_cast<Uint8*>(pCoarseMip) + row * CoarseMipStride)[col * NumChannels + c];
+ if( IsSRGB )
+ DstCol = SRGBAverage( Col00, Col01, Col10, Col11 );
+ else
+ DstCol = (Col00 + Col01 + Col10 + Col11)/4;
+ }
+ }
+ }
+
+ template < typename ChannelType >
+ void RGBToRGBA(const void *pRGBData, Uint32 RGBStride,
+ void *pRGBAData, Uint32 RGBAStride,
+ Uint32 Width, Uint32 Height)
+ {
+ for( Uint32 row = 0; row < Height; ++row )
+ for( Uint32 col = 0; col < Width; ++col )
+ {
+ for( int c = 0; c < 3; ++c )
+ {
+ reinterpret_cast<ChannelType*>( (reinterpret_cast<Uint8*>(pRGBAData) + RGBAStride * row) ) [col *4 + c] =
+ reinterpret_cast<const ChannelType*>( (reinterpret_cast<const Uint8*>(pRGBData) + RGBStride * row))[col*3 + c];
+ }
+ reinterpret_cast<ChannelType*>( (reinterpret_cast<Uint8*>(pRGBAData) + RGBAStride * row) ) [col *4 + 3] = std::numeric_limits<ChannelType>::max();
+ }
+ }
+
+ void CreateTextureFromImage( Image *pSrcImage,
+ const TextureLoadInfo& TexLoadInfo,
+ Diligent::IRenderDevice *pDevice,
+ Diligent::ITexture **ppTexture )
+ {
+ const auto& ImgDesc = pSrcImage->GetDesc();
+ TextureDesc TexDesc;
+ TexDesc.Type = TEXTURE_TYPE_2D;
+ TexDesc.Width = ImgDesc.Width;
+ TexDesc.Height = ImgDesc.Height;
+ TexDesc.MipLevels = ComputeMipLevelsCount( TexDesc.Width, TexDesc.Height );
+ if( TexLoadInfo.MipLevels > 0 )
+ TexDesc.MipLevels = std::min(TexDesc.MipLevels, TexLoadInfo.MipLevels);
+ TexDesc.Usage = TexLoadInfo.Usage;
+ TexDesc.BindFlags = TexLoadInfo.BindFlags;
+ TexDesc.Format = TexLoadInfo.Format;
+ TexDesc.CPUAccessFlags = TexLoadInfo.CPUAccessFlags;
+ auto ChannelDepth = ImgDesc.BitsPerPixel / ImgDesc.NumComponents;
+
+ Uint32 NumComponents = ImgDesc.NumComponents == 3 ? 4 : ImgDesc.NumComponents;
+ bool IsSRGB = (ImgDesc.NumComponents >= 3 && ChannelDepth == 8) ? TexLoadInfo.IsSRGB : false;
+ if( TexDesc.Format == TEX_FORMAT_UNKNOWN )
+ {
+ if( ChannelDepth == 8 )
+ {
+ switch( NumComponents )
+ {
+ case 1: TexDesc.Format = TEX_FORMAT_R8_UNORM; break;
+ case 2: TexDesc.Format = TEX_FORMAT_RG8_UNORM; break;
+ case 4: TexDesc.Format = IsSRGB ? TEX_FORMAT_RGBA8_UNORM_SRGB : TEX_FORMAT_RGBA8_UNORM; break;
+ default: LOG_ERROR_AND_THROW( "Unexpected number of color channels (", ImgDesc.NumComponents, ")" );
+ }
+ }
+ else if( ChannelDepth == 16 )
+ {
+ switch( NumComponents )
+ {
+ case 1: TexDesc.Format = TEX_FORMAT_R16_UNORM; break;
+ case 2: TexDesc.Format = TEX_FORMAT_RG16_UNORM; break;
+ case 4: TexDesc.Format = TEX_FORMAT_RGBA16_UNORM; break;
+ default: LOG_ERROR_AND_THROW( "Unexpected number of color channels (", ImgDesc.NumComponents, ")" );
+ }
+ }
+ else
+ LOG_ERROR_AND_THROW( "Unsupported color channel depth (", ChannelDepth, ")" );
+ }
+ else
+ {
+ const auto& TexFmtDesc = GetTextureFormatAttribs( TexDesc.Format );
+ if( TexFmtDesc.NumComponents != NumComponents )
+ LOG_ERROR_AND_THROW( "Incorrect number of components ", ImgDesc.NumComponents, ") for texture format ", TexFmtDesc.Name );
+ if( TexFmtDesc.ComponentSize != ChannelDepth / 8 )
+ LOG_ERROR_AND_THROW( "Incorrect channel size ", ChannelDepth, ") for texture format ", TexFmtDesc.Name );
+ }
+
+
+ std::vector<TextureSubResData> pSubResources(TexDesc.MipLevels);
+ std::vector< std::vector<Uint8> > Mips(TexDesc.MipLevels);
+
+ if( ImgDesc.NumComponents == 3 )
+ {
+ VERIFY_EXPR( NumComponents == 4 );
+ auto RGBAStride = ImgDesc.Width * NumComponents * ChannelDepth / 8;
+ RGBAStride = (RGBAStride + 3) & (-4);
+ Mips[0].resize(RGBAStride * ImgDesc.Height);
+ pSubResources[0].pData = Mips[0].data();
+ pSubResources[0].Stride = RGBAStride;
+ if( ChannelDepth == 8 )
+ RGBToRGBA<Uint8>( pSrcImage->GetData()->GetDataPtr(), ImgDesc.RowStride,
+ Mips[0].data(), RGBAStride,
+ ImgDesc.Width, ImgDesc.Height);
+ else if( ChannelDepth == 16 )
+ RGBToRGBA<Uint16>( pSrcImage->GetData()->GetDataPtr(), ImgDesc.RowStride,
+ Mips[0].data(), RGBAStride,
+ ImgDesc.Width, ImgDesc.Height);
+ }
+ else
+ {
+ pSubResources[0].pData = pSrcImage->GetData()->GetDataPtr();
+ pSubResources[0].Stride = ImgDesc.RowStride;
+ }
+
+ auto MipWidth = TexDesc.Width;
+ auto MipHeight = TexDesc.Height;
+ for( Uint32 m = 1; m < TexDesc.MipLevels; ++m )
+ {
+ auto CoarseMipWidth = std::max(MipWidth/2u, 1u);
+ auto CoarseMipHeight = std::max(MipHeight/2u, 1u);
+ auto CoarseMipStride = CoarseMipWidth * NumComponents * ChannelDepth / 8;
+ CoarseMipStride = (CoarseMipStride + 3) & (-4);
+ Mips[m].resize(CoarseMipStride * CoarseMipHeight);
+
+ if( ChannelDepth == 8 )
+ ComputeCoarseMip<Uint8>( NumComponents, IsSRGB,
+ pSubResources[m-1].pData, pSubResources[m-1].Stride,
+ Mips[m].data(), CoarseMipStride,
+ CoarseMipWidth, CoarseMipHeight);
+ else if( ChannelDepth == 16 )
+ ComputeCoarseMip<Uint16>( NumComponents, IsSRGB,
+ pSubResources[m-1].pData, pSubResources[m-1].Stride,
+ Mips[m].data(), CoarseMipStride,
+ CoarseMipWidth, CoarseMipHeight);
+
+ pSubResources[m].pData = Mips[m].data();
+ pSubResources[m].Stride = CoarseMipStride;
+
+ MipWidth = CoarseMipWidth;
+ MipHeight = CoarseMipHeight;
+ }
+
+ TextureData TexData;
+ TexData.pSubResources = pSubResources.data();
+ TexData.NumSubresources = TexDesc.MipLevels;
+
+ pDevice->CreateTexture( TexDesc, TexData, ppTexture );
+ }
+
+ void CreateTextureFromDDS( IDataBlob *pDDSData,
+ const TextureLoadInfo& TexLoadInfo,
+ Diligent::IRenderDevice *pDevice,
+ Diligent::ITexture **ppTexture )
+ {
+ CreateDDSTextureFromMemoryEx(pDevice,
+ reinterpret_cast<const Uint8*>(pDDSData->GetDataPtr()),
+ static_cast<size_t>(pDDSData->GetSize()),
+ 0, // maxSize
+ TexLoadInfo.Usage,
+ TexLoadInfo.BindFlags,
+ TexLoadInfo.CPUAccessFlags,
+ 0, // miscFlags
+ false, // forceSRGB
+ ppTexture );
+ }
+}
diff --git a/TextureLoader/src/TextureUtilities.cpp b/TextureLoader/src/TextureUtilities.cpp
new file mode 100644
index 0000000..2ee94ba
--- /dev/null
+++ b/TextureLoader/src/TextureUtilities.cpp
@@ -0,0 +1,95 @@
+/* Copyright 2015 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "TextureUtilities.h"
+#include "Errors.h"
+#include "TextureLoader.h"
+#include "Image.h"
+#include "BasicFileStream.h"
+#include "RefCntAutoPtr.h"
+#include "DataBlobImpl.h"
+#include <algorithm>
+
+using namespace Diligent;
+
+namespace Diligent
+{
+
+void CreateImageFromFile( const Diligent::Char *FilePath,
+ Image **ppImage,
+ IDataBlob **ppDDSData)
+{
+ auto *pDotPos = strrchr( FilePath, '.' );
+ if( pDotPos == nullptr )
+ LOG_ERROR_AND_THROW( "File path ", FilePath, " does not contain extension" );
+
+ auto *pExtension = pDotPos + 1;
+ if( *pExtension == 0 )
+ LOG_ERROR_AND_THROW( "File path ", FilePath, " contains empty extension" );
+
+ String Extension(pExtension);
+ std::transform( Extension.begin(), Extension.end(), Extension.begin(), ::tolower );
+
+ Diligent::RefCntAutoPtr<BasicFileStream> pFileStream( new BasicFileStream( FilePath, EFileAccessMode::Read ) );
+
+ if( Extension == "dds" )
+ {
+ VERIFY_EXPR(ppDDSData != nullptr);
+ *ppDDSData = new DataBlobImpl;
+ pFileStream->Read(*ppDDSData);
+ (*ppDDSData)->AddRef();
+ }
+ else
+ {
+ ImageLoadInfo ImgLoadInfo;
+ if( Extension == "png" )
+ ImgLoadInfo.Format = EImageFileFormat::png;
+ else if( Extension == "jpeg" || Extension == "jpg" )
+ ImgLoadInfo.Format = EImageFileFormat::jpeg;
+ else if( Extension == "tiff" || Extension == "tif" )
+ ImgLoadInfo.Format = EImageFileFormat::tiff;
+ else
+ LOG_ERROR_AND_THROW( "Unsupported file format ", Extension );
+
+ *ppImage = new Image(pFileStream, ImgLoadInfo);
+ (*ppImage)->AddRef();
+ }
+}
+
+void CreateTextureFromFile( const Diligent::Char *FilePath,
+ const TextureLoadInfo& TexLoadInfo,
+ IRenderDevice *pDevice,
+ ITexture **ppTexture )
+{
+ RefCntAutoPtr<Image> pImage;
+ RefCntAutoPtr<IDataBlob> pDDSData;
+ CreateImageFromFile( FilePath, &pImage, &pDDSData );
+
+ if( pImage )
+ CreateTextureFromImage( pImage, TexLoadInfo, pDevice, ppTexture );
+ else if(pDDSData)
+ CreateTextureFromDDS( pDDSData, TexLoadInfo, pDevice, ppTexture );
+}
+
+}
diff --git a/TextureLoader/src/pch.cpp b/TextureLoader/src/pch.cpp
new file mode 100644
index 0000000..4a893f2
--- /dev/null
+++ b/TextureLoader/src/pch.cpp
@@ -0,0 +1,25 @@
+/* Copyright 2015 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+