msvcrt: Move btowc implementation to mbcs.c file.
[wine.git] / dlls / windowscodecs / ddsformat.c
blobd0932767d6f436e2dfefaecc7a326e14748fcd35
1 /*
2 * Copyright 2020 Ziqing Hui
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * Note:
21 * Uncompressed image:
22 * For uncompressed formats, a block is equivalent to a pixel.
24 * Cube map:
25 * A cube map is equivalent to a 2D texture array which has 6 textures.
26 * A cube map array is equivalent to a 2D texture array which has cubeCount*6 textures.
29 #include "config.h"
30 #include "wine/port.h"
32 #include <stdarg.h>
34 #define COBJMACROS
36 #include "windef.h"
37 #include "winbase.h"
38 #include "objbase.h"
40 #include "wincodecs_private.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
46 #define DDS_MAGIC 0x20534444
47 #ifndef MAKEFOURCC
48 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
49 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
50 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
51 #endif
53 #define GET_RGB565_R(color) ((BYTE)(((color) >> 11) & 0x1F))
54 #define GET_RGB565_G(color) ((BYTE)(((color) >> 5) & 0x3F))
55 #define GET_RGB565_B(color) ((BYTE)(((color) >> 0) & 0x1F))
56 #define MAKE_RGB565(r, g, b) ((WORD)(((BYTE)(r) << 11) | ((BYTE)(g) << 5) | (BYTE)(b)))
57 #define MAKE_ARGB(a, r, g, b) (((DWORD)(a) << 24) | ((DWORD)(r) << 16) | ((DWORD)(g) << 8) | (DWORD)(b))
59 #define DDPF_ALPHAPIXELS 0x00000001
60 #define DDPF_ALPHA 0x00000002
61 #define DDPF_FOURCC 0x00000004
62 #define DDPF_PALETTEINDEXED8 0x00000020
63 #define DDPF_RGB 0x00000040
64 #define DDPF_LUMINANCE 0x00020000
65 #define DDPF_BUMPDUDV 0x00080000
67 #define DDSCAPS2_CUBEMAP 0x00000200
68 #define DDSCAPS2_VOLUME 0x00200000
70 #define DDS_DIMENSION_TEXTURE1D 2
71 #define DDS_DIMENSION_TEXTURE2D 3
72 #define DDS_DIMENSION_TEXTURE3D 4
74 #define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004
76 #define DDS_BLOCK_WIDTH 4
77 #define DDS_BLOCK_HEIGHT 4
79 typedef struct {
80 DWORD size;
81 DWORD flags;
82 DWORD fourCC;
83 DWORD rgbBitCount;
84 DWORD rBitMask;
85 DWORD gBitMask;
86 DWORD bBitMask;
87 DWORD aBitMask;
88 } DDS_PIXELFORMAT;
90 typedef struct {
91 DWORD size;
92 DWORD flags;
93 DWORD height;
94 DWORD width;
95 DWORD pitchOrLinearSize;
96 DWORD depth;
97 DWORD mipMapCount;
98 DWORD reserved1[11];
99 DDS_PIXELFORMAT ddspf;
100 DWORD caps;
101 DWORD caps2;
102 DWORD caps3;
103 DWORD caps4;
104 DWORD reserved2;
105 } DDS_HEADER;
107 typedef struct {
108 DWORD dxgiFormat;
109 DWORD resourceDimension;
110 DWORD miscFlag;
111 DWORD arraySize;
112 DWORD miscFlags2;
113 } DDS_HEADER_DXT10;
115 typedef struct dds_info {
116 UINT width;
117 UINT height;
118 UINT depth;
119 UINT mip_levels;
120 UINT array_size;
121 UINT frame_count;
122 UINT data_offset;
123 UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/
124 DXGI_FORMAT format;
125 WICDdsDimension dimension;
126 WICDdsAlphaMode alpha_mode;
127 const GUID *pixel_format;
128 UINT pixel_format_bpp;
129 } dds_info;
131 typedef struct dds_frame_info {
132 UINT width;
133 UINT height;
134 DXGI_FORMAT format;
135 UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/
136 UINT block_width;
137 UINT block_height;
138 UINT width_in_blocks;
139 UINT height_in_blocks;
140 const GUID *pixel_format;
141 UINT pixel_format_bpp;
142 } dds_frame_info;
144 typedef struct DdsDecoder {
145 IWICBitmapDecoder IWICBitmapDecoder_iface;
146 IWICDdsDecoder IWICDdsDecoder_iface;
147 IWICWineDecoder IWICWineDecoder_iface;
148 LONG ref;
149 BOOL initialized;
150 IStream *stream;
151 CRITICAL_SECTION lock;
152 dds_info info;
153 } DdsDecoder;
155 typedef struct DdsFrameDecode {
156 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
157 IWICDdsFrameDecode IWICDdsFrameDecode_iface;
158 LONG ref;
159 BYTE *block_data;
160 BYTE *pixel_data;
161 CRITICAL_SECTION lock;
162 dds_frame_info info;
163 } DdsFrameDecode;
165 static struct dds_format {
166 DDS_PIXELFORMAT pixel_format;
167 const GUID *wic_format;
168 UINT wic_format_bpp;
169 DXGI_FORMAT dxgi_format;
170 } dds_format_table[] = {
171 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 },
172 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC1_UNORM },
173 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 },
174 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC2_UNORM },
175 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 },
176 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC2_UNORM },
177 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 },
178 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC3_UNORM },
179 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 },
180 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC3_UNORM },
181 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 },
182 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
183 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 },
184 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_SNORM },
185 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 },
186 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
187 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 },
188 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_SNORM },
189 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 },
190 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
191 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 },
192 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
193 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 },
194 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_R8G8_B8G8_UNORM },
195 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 },
196 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_G8R8_G8B8_UNORM },
197 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 },
198 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN },
199 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 },
200 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
201 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 },
202 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_SNORM },
203 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 },
204 &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
205 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 },
206 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_FLOAT },
207 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 },
208 &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
209 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 },
210 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
211 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 },
212 &GUID_WICPixelFormatUndefined, 32, DXGI_FORMAT_R32G32_FLOAT },
213 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 },
214 &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
215 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 },
216 &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
217 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0 },
218 &GUID_WICPixelFormat32bppRGB, 32, DXGI_FORMAT_UNKNOWN },
219 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 },
220 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
221 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 },
222 &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
223 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
224 * For "correct" one, the RGB masks should be 0x3FF,0xFFC00,0x3FF00000.
225 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
226 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF00000,0xFFC00,0x3FF,0xC0000000 },
227 &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
228 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 },
229 &GUID_WICPixelFormat32bppRGBA1010102, 32, DXGI_FORMAT_UNKNOWN },
230 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 },
231 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_UNORM },
232 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 },
233 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
234 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0xFF0000,0x00FF00,0x0000FF,0 },
235 &GUID_WICPixelFormat24bppBGR, 24, DXGI_FORMAT_UNKNOWN },
236 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0x0000FF,0x00FF00,0xFF0000,0 },
237 &GUID_WICPixelFormat24bppRGB, 24, DXGI_FORMAT_UNKNOWN },
238 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 },
239 &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
240 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0 },
241 &GUID_WICPixelFormat16bppBGR555, 16, DXGI_FORMAT_UNKNOWN },
242 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 },
243 &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
244 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 },
245 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_B4G4R4A4_UNORM },
246 { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF },
247 &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
248 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 },
249 &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
250 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 },
251 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R8G8_UNORM },
252 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 },
253 &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
254 { { 0 }, &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
255 { { 0 }, &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
256 { { 0 }, &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
257 { { 0 }, &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
258 { { 0 }, &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
259 { { 0 }, &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
260 { { 0 }, &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
261 { { 0 }, &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
262 { { 0 }, &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
263 { { 0 }, &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
264 { { 0 }, &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
265 { { 0 }, &GUID_WICPixelFormat32bppRGBE, 32, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
266 { { 0 }, &GUID_WICPixelFormat32bppRGBA1010102XR, 32, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },
267 { { 0 }, &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
268 { { 0 }, &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
269 { { 0 }, &GUID_WICPixelFormat96bppRGBFloat, 96, DXGI_FORMAT_R32G32B32_FLOAT },
270 { { 0 }, &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
271 { { 0 }, &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN }
274 static DXGI_FORMAT compressed_formats[] = {
275 DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB,
276 DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB,
277 DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB,
278 DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM,
279 DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM,
280 DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16,
281 DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB
284 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **);
286 static DWORD rgb565_to_argb(WORD color, BYTE alpha)
288 return MAKE_ARGB(alpha, (GET_RGB565_R(color) * 0xFF + 0x0F) / 0x1F,
289 (GET_RGB565_G(color) * 0xFF + 0x1F) / 0x3F,
290 (GET_RGB565_B(color) * 0xFF + 0x0F) / 0x1F);
293 static inline BOOL has_extended_header(DDS_HEADER *header)
295 return (header->ddspf.flags & DDPF_FOURCC) &&
296 (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'));
299 static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
301 if (header_dxt10) {
302 if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube;
303 switch (header_dxt10->resourceDimension)
305 case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D;
306 case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D;
307 case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D;
308 default: return WICDdsTexture2D;
310 } else {
311 if (header->caps2 & DDSCAPS2_CUBEMAP) {
312 return WICDdsTextureCube;
313 } else if (header->caps2 & DDSCAPS2_VOLUME) {
314 return WICDdsTexture3D;
315 } else {
316 return WICDdsTexture2D;
321 static struct dds_format *get_dds_format(DDS_PIXELFORMAT *pixel_format)
323 UINT i;
325 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
327 if ((pixel_format->flags & dds_format_table[i].pixel_format.flags) &&
328 (pixel_format->fourCC == dds_format_table[i].pixel_format.fourCC) &&
329 (pixel_format->rgbBitCount == dds_format_table[i].pixel_format.rgbBitCount) &&
330 (pixel_format->rBitMask == dds_format_table[i].pixel_format.rBitMask) &&
331 (pixel_format->gBitMask == dds_format_table[i].pixel_format.gBitMask) &&
332 (pixel_format->bBitMask == dds_format_table[i].pixel_format.bBitMask) &&
333 (pixel_format->aBitMask == dds_format_table[i].pixel_format.aBitMask))
334 return dds_format_table + i;
337 return dds_format_table + ARRAY_SIZE(dds_format_table) - 1;
340 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
342 switch (fourcc)
344 case MAKEFOURCC('D', 'X', 'T', '1'):
345 case MAKEFOURCC('D', 'X', 'T', '2'):
346 case MAKEFOURCC('D', 'X', 'T', '4'):
347 return WICDdsAlphaModePremultiplied;
348 default:
349 return WICDdsAlphaModeUnknown;
353 static UINT get_bytes_per_block_from_format(DXGI_FORMAT format)
355 /* for uncompressed format, return bytes per pixel*/
356 switch (format)
358 case DXGI_FORMAT_R8_TYPELESS:
359 case DXGI_FORMAT_R8_UNORM:
360 case DXGI_FORMAT_R8_UINT:
361 case DXGI_FORMAT_R8_SNORM:
362 case DXGI_FORMAT_R8_SINT:
363 case DXGI_FORMAT_A8_UNORM:
364 return 1;
365 case DXGI_FORMAT_R8G8_TYPELESS:
366 case DXGI_FORMAT_R8G8_UNORM:
367 case DXGI_FORMAT_R8G8_UINT:
368 case DXGI_FORMAT_R8G8_SNORM:
369 case DXGI_FORMAT_R8G8_SINT:
370 case DXGI_FORMAT_R16_TYPELESS:
371 case DXGI_FORMAT_R16_FLOAT:
372 case DXGI_FORMAT_D16_UNORM:
373 case DXGI_FORMAT_R16_UNORM:
374 case DXGI_FORMAT_R16_UINT:
375 case DXGI_FORMAT_R16_SNORM:
376 case DXGI_FORMAT_R16_SINT:
377 case DXGI_FORMAT_B5G6R5_UNORM:
378 case DXGI_FORMAT_B5G5R5A1_UNORM:
379 case DXGI_FORMAT_B4G4R4A4_UNORM:
380 return 2;
381 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
382 case DXGI_FORMAT_R10G10B10A2_UNORM:
383 case DXGI_FORMAT_R10G10B10A2_UINT:
384 case DXGI_FORMAT_R11G11B10_FLOAT:
385 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
386 case DXGI_FORMAT_R8G8B8A8_UNORM:
387 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
388 case DXGI_FORMAT_R8G8B8A8_UINT:
389 case DXGI_FORMAT_R8G8B8A8_SNORM:
390 case DXGI_FORMAT_R8G8B8A8_SINT:
391 case DXGI_FORMAT_R16G16_TYPELESS:
392 case DXGI_FORMAT_R16G16_FLOAT:
393 case DXGI_FORMAT_R16G16_UNORM:
394 case DXGI_FORMAT_R16G16_UINT:
395 case DXGI_FORMAT_R16G16_SNORM:
396 case DXGI_FORMAT_R16G16_SINT:
397 case DXGI_FORMAT_R32_TYPELESS:
398 case DXGI_FORMAT_D32_FLOAT:
399 case DXGI_FORMAT_R32_FLOAT:
400 case DXGI_FORMAT_R32_UINT:
401 case DXGI_FORMAT_R32_SINT:
402 case DXGI_FORMAT_R24G8_TYPELESS:
403 case DXGI_FORMAT_D24_UNORM_S8_UINT:
404 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
405 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
406 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
407 case DXGI_FORMAT_R8G8_B8G8_UNORM:
408 case DXGI_FORMAT_G8R8_G8B8_UNORM:
409 case DXGI_FORMAT_B8G8R8A8_UNORM:
410 case DXGI_FORMAT_B8G8R8X8_UNORM:
411 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
412 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
413 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
414 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
415 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
416 return 4;
417 case DXGI_FORMAT_BC1_UNORM:
418 case DXGI_FORMAT_BC1_TYPELESS:
419 case DXGI_FORMAT_BC1_UNORM_SRGB:
420 case DXGI_FORMAT_BC4_TYPELESS:
421 case DXGI_FORMAT_BC4_UNORM:
422 case DXGI_FORMAT_BC4_SNORM:
423 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
424 case DXGI_FORMAT_R16G16B16A16_FLOAT:
425 case DXGI_FORMAT_R16G16B16A16_UNORM:
426 case DXGI_FORMAT_R16G16B16A16_UINT:
427 case DXGI_FORMAT_R16G16B16A16_SNORM:
428 case DXGI_FORMAT_R16G16B16A16_SINT:
429 case DXGI_FORMAT_R32G32_TYPELESS:
430 case DXGI_FORMAT_R32G32_FLOAT:
431 case DXGI_FORMAT_R32G32_UINT:
432 case DXGI_FORMAT_R32G32_SINT:
433 case DXGI_FORMAT_R32G8X24_TYPELESS:
434 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
435 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
436 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
437 return 8;
438 case DXGI_FORMAT_R32G32B32_TYPELESS:
439 case DXGI_FORMAT_R32G32B32_FLOAT:
440 case DXGI_FORMAT_R32G32B32_UINT:
441 case DXGI_FORMAT_R32G32B32_SINT:
442 return 12;
443 case DXGI_FORMAT_BC2_UNORM:
444 case DXGI_FORMAT_BC2_TYPELESS:
445 case DXGI_FORMAT_BC2_UNORM_SRGB:
446 case DXGI_FORMAT_BC3_UNORM:
447 case DXGI_FORMAT_BC3_TYPELESS:
448 case DXGI_FORMAT_BC3_UNORM_SRGB:
449 case DXGI_FORMAT_BC5_TYPELESS:
450 case DXGI_FORMAT_BC5_UNORM:
451 case DXGI_FORMAT_BC5_SNORM:
452 case DXGI_FORMAT_BC6H_TYPELESS:
453 case DXGI_FORMAT_BC6H_UF16:
454 case DXGI_FORMAT_BC6H_SF16:
455 case DXGI_FORMAT_BC7_TYPELESS:
456 case DXGI_FORMAT_BC7_UNORM:
457 case DXGI_FORMAT_BC7_UNORM_SRGB:
458 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
459 case DXGI_FORMAT_R32G32B32A32_FLOAT:
460 case DXGI_FORMAT_R32G32B32A32_UINT:
461 case DXGI_FORMAT_R32G32B32A32_SINT:
462 return 16;
463 default:
464 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
465 return 0;
469 static const GUID *dxgi_format_to_wic_format(DXGI_FORMAT dxgi_format)
471 UINT i;
472 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
474 if (dds_format_table[i].pixel_format.size == 0 &&
475 dds_format_table[i].dxgi_format == dxgi_format)
476 return dds_format_table[i].wic_format;
478 return &GUID_WICPixelFormatUndefined;
481 static BOOL is_compressed(DXGI_FORMAT format)
483 UINT i;
485 for (i = 0; i < ARRAY_SIZE(compressed_formats); i++)
487 if (format == compressed_formats[i]) return TRUE;
489 return FALSE;
492 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
494 int i;
495 UINT depth;
496 struct dds_format *format_info;
498 info->width = header->width;
499 info->height = header->height;
500 info->depth = 1;
501 info->mip_levels = 1;
502 info->array_size = 1;
503 if (header->depth) info->depth = header->depth;
504 if (header->mipMapCount) info->mip_levels = header->mipMapCount;
506 if (has_extended_header(header)) {
507 if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize;
508 info->format = header_dxt10->dxgiFormat;
509 info->dimension = get_dimension(NULL, header_dxt10);
510 info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008;
511 info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10);
512 if (is_compressed(info->format)) {
513 info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ?
514 &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA;
515 info->pixel_format_bpp = 32;
516 } else {
517 info->pixel_format = dxgi_format_to_wic_format(info->format);
518 info->pixel_format_bpp = get_bytes_per_block_from_format(info->format) * 8;
520 } else {
521 format_info = get_dds_format(&header->ddspf);
522 info->format = format_info->dxgi_format;
523 info->dimension = get_dimension(header, NULL);
524 info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC);
525 info->data_offset = sizeof(DWORD) + sizeof(*header);
526 info->pixel_format = format_info->wic_format;
527 info->pixel_format_bpp = format_info->wic_format_bpp;
530 if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) {
531 info->bytes_per_block = header->ddspf.rgbBitCount / 8;
532 } else {
533 info->bytes_per_block = get_bytes_per_block_from_format(info->format);
536 /* get frame count */
538 if (info->depth == 1) {
539 info->frame_count = info->array_size * info->mip_levels;
540 } else {
541 info->frame_count = 0;
542 depth = info->depth;
543 for (i = 0; i < info->mip_levels; i++)
545 info->frame_count += depth;
546 if (depth > 1) depth /= 2;
548 info->frame_count *= info->array_size;
550 if (info->dimension == WICDdsTextureCube) info->frame_count *= 6;
553 static void decode_block(const BYTE *block_data, UINT block_count, DXGI_FORMAT format,
554 UINT width, UINT height, DWORD *buffer)
556 const BYTE *block, *color_indices, *alpha_indices, *alpha_table;
557 int i, j, x, y, block_x, block_y, color_index, alpha_index;
558 int block_size, color_offset, color_indices_offset;
559 WORD color[4], color_value = 0;
560 BYTE alpha[8], alpha_value = 0;
562 if (format == DXGI_FORMAT_BC1_UNORM) {
563 block_size = 8;
564 color_offset = 0;
565 color_indices_offset = 4;
566 } else {
567 block_size = 16;
568 color_offset = 8;
569 color_indices_offset = 12;
571 block_x = 0;
572 block_y = 0;
574 for (i = 0; i < block_count; i++)
576 block = block_data + i * block_size;
578 color[0] = *((WORD *)(block + color_offset));
579 color[1] = *((WORD *)(block + color_offset + 2));
580 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) * 2 + GET_RGB565_R(color[1]) + 1) / 3),
581 ((GET_RGB565_G(color[0]) * 2 + GET_RGB565_G(color[1]) + 1) / 3),
582 ((GET_RGB565_B(color[0]) * 2 + GET_RGB565_B(color[1]) + 1) / 3));
583 color[3] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) * 2 + 1) / 3),
584 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) * 2 + 1) / 3),
585 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) * 2 + 1) / 3));
587 switch (format)
589 case DXGI_FORMAT_BC1_UNORM:
590 if (color[0] <= color[1]) {
591 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) + 1) / 2),
592 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) + 1) / 2),
593 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) + 1) / 2));
594 color[3] = 0;
596 break;
597 case DXGI_FORMAT_BC2_UNORM:
598 alpha_table = block;
599 break;
600 case DXGI_FORMAT_BC3_UNORM:
601 alpha[0] = *block;
602 alpha[1] = *(block + 1);
603 if (alpha[0] > alpha[1]) {
604 for (j = 2; j < 8; j++)
606 alpha[j] = (BYTE)((alpha[0] * (8 - j) + alpha[1] * (j - 1) + 3) / 7);
608 } else {
609 for (j = 2; j < 6; j++)
611 alpha[j] = (BYTE)((alpha[0] * (6 - j) + alpha[1] * (j - 1) + 2) / 5);
613 alpha[6] = 0;
614 alpha[7] = 0xFF;
616 alpha_indices = block + 2;
617 break;
618 default:
619 break;
622 color_indices = block + color_indices_offset;
623 for (j = 0; j < 16; j++)
625 x = block_x + j % 4;
626 y = block_y + j / 4;
627 if (x >= width || y >= height) continue;
629 color_index = (color_indices[j / 4] >> ((j % 4) * 2)) & 0x3;
630 color_value = color[color_index];
632 switch (format)
634 case DXGI_FORMAT_BC1_UNORM:
635 if ((color[0] <= color[1]) && !color_value) {
636 color_value = 0;
637 alpha_value = 0;
638 } else {
639 alpha_value = 0xFF;
641 break;
642 case DXGI_FORMAT_BC2_UNORM:
643 alpha_value = (alpha_table[j / 2] >> (j % 2) * 4) & 0xF;
644 alpha_value = (BYTE)((alpha_value * 0xFF + 0x7)/ 0xF);
645 break;
646 case DXGI_FORMAT_BC3_UNORM:
647 alpha_index = (*((DWORD *)(alpha_indices + (j / 8) * 3)) >> ((j % 8) * 3)) & 0x7;
648 alpha_value = alpha[alpha_index];
649 break;
650 default:
651 break;
653 buffer[x + y * width] = rgb565_to_argb(color_value, alpha_value);
656 block_x += DDS_BLOCK_WIDTH;
657 if (block_x >= width) {
658 block_x = 0;
659 block_y += DDS_BLOCK_HEIGHT;
664 static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
666 return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface);
669 static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface)
671 return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface);
674 static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface)
676 return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface);
679 static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
681 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface);
684 static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface)
686 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface);
689 static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
690 void **ppv)
692 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
693 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
695 if (!ppv) return E_INVALIDARG;
697 if (IsEqualIID(&IID_IUnknown, iid) ||
698 IsEqualIID(&IID_IWICBitmapSource, iid) ||
699 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) {
700 *ppv = &This->IWICBitmapFrameDecode_iface;
701 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) {
702 *ppv = &This->IWICDdsFrameDecode_iface;
703 } else {
704 *ppv = NULL;
705 return E_NOINTERFACE;
708 IUnknown_AddRef((IUnknown*)*ppv);
709 return S_OK;
712 static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
714 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
715 ULONG ref = InterlockedIncrement(&This->ref);
717 TRACE("(%p) refcount=%u\n", iface, ref);
719 return ref;
722 static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface)
724 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
725 ULONG ref = InterlockedDecrement(&This->ref);
727 TRACE("(%p) refcount=%u\n", iface, ref);
729 if (ref == 0) {
730 if (This->pixel_data != This->block_data) HeapFree(GetProcessHeap(), 0, This->pixel_data);
731 HeapFree(GetProcessHeap(), 0, This->block_data);
732 HeapFree(GetProcessHeap(), 0, This);
735 return ref;
738 static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
739 UINT *puiWidth, UINT *puiHeight)
741 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
743 if (!puiWidth || !puiHeight) return E_INVALIDARG;
745 *puiWidth = This->info.width;
746 *puiHeight = This->info.height;
748 TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight);
750 return S_OK;
753 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
754 WICPixelFormatGUID *pPixelFormat)
756 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
758 if (!pPixelFormat) return E_INVALIDARG;
760 *pPixelFormat = *This->info.pixel_format;
762 TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat));
764 return S_OK;
767 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
768 double *pDpiX, double *pDpiY)
770 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
772 return E_NOTIMPL;
775 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
776 IWICPalette *pIPalette)
778 FIXME("(%p,%p): stub.\n", iface, pIPalette);
780 return E_NOTIMPL;
783 static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
784 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
786 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
787 UINT bpp, frame_stride, frame_size;
788 INT x, y, width, height;
789 HRESULT hr;
791 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
793 if (!pbBuffer) return E_INVALIDARG;
795 bpp = This->info.pixel_format_bpp;
796 if (!bpp) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
798 frame_stride = This->info.width * bpp / 8;
799 frame_size = frame_stride * This->info.height;
800 if (!prc) {
801 if (cbStride < frame_stride) return E_INVALIDARG;
802 if (cbBufferSize < frame_size) return WINCODEC_ERR_INSUFFICIENTBUFFER;
803 } else {
804 x = prc->X;
805 y = prc->Y;
806 width = prc->Width;
807 height = prc->Height;
808 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
809 x + width > This->info.width ||
810 y + height > This->info.height) {
811 return E_INVALIDARG;
813 if (cbStride < width * bpp / 8) return E_INVALIDARG;
814 if (cbBufferSize < cbStride * height) return WINCODEC_ERR_INSUFFICIENTBUFFER;
817 EnterCriticalSection(&This->lock);
819 if (!This->pixel_data) {
820 if (is_compressed(This->info.format)) {
821 This->pixel_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
822 if (!This->pixel_data) {
823 hr = E_OUTOFMEMORY;
824 goto end;
826 decode_block(This->block_data, This->info.width_in_blocks * This->info.height_in_blocks, This->info.format,
827 This->info.width, This->info.height, (DWORD *)This->pixel_data);
828 } else {
829 This->pixel_data = This->block_data;
833 hr = copy_pixels(bpp, This->pixel_data, This->info.width, This->info.height, frame_stride,
834 prc, cbStride, cbBufferSize, pbBuffer);
836 end:
837 LeaveCriticalSection(&This->lock);
839 return hr;
842 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
843 IWICMetadataQueryReader **ppIMetadataQueryReader)
845 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
847 return E_NOTIMPL;
850 static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
851 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
853 FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount);
855 return E_NOTIMPL;
858 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
859 IWICBitmapSource **ppIThumbnail)
861 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
863 return E_NOTIMPL;
866 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = {
867 DdsFrameDecode_QueryInterface,
868 DdsFrameDecode_AddRef,
869 DdsFrameDecode_Release,
870 DdsFrameDecode_GetSize,
871 DdsFrameDecode_GetPixelFormat,
872 DdsFrameDecode_GetResolution,
873 DdsFrameDecode_CopyPalette,
874 DdsFrameDecode_CopyPixels,
875 DdsFrameDecode_GetMetadataQueryReader,
876 DdsFrameDecode_GetColorContexts,
877 DdsFrameDecode_GetThumbnail
880 static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface,
881 REFIID iid, void **ppv)
883 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
884 return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
887 static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface)
889 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
890 return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
893 static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface)
895 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
896 return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
899 static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface,
900 UINT *widthInBlocks, UINT *heightInBlocks)
902 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
904 if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG;
906 *widthInBlocks = This->info.width_in_blocks;
907 *heightInBlocks = This->info.height_in_blocks;
909 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks);
911 return S_OK;
914 static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface,
915 WICDdsFormatInfo *formatInfo)
917 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
919 if (!formatInfo) return E_INVALIDARG;
921 formatInfo->DxgiFormat = This->info.format;
922 formatInfo->BytesPerBlock = This->info.bytes_per_block;
923 formatInfo->BlockWidth = This->info.block_width;
924 formatInfo->BlockHeight = This->info.block_height;
926 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo,
927 formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight);
929 return S_OK;
932 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
933 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
934 BYTE *buffer)
936 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
937 int x, y, width, height;
938 UINT bytes_per_block, frame_stride, frame_size;
940 TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer);
942 if (!buffer) return E_INVALIDARG;
944 bytes_per_block = This->info.bytes_per_block;
945 frame_stride = This->info.width_in_blocks * bytes_per_block;
946 frame_size = frame_stride * This->info.height_in_blocks;
948 if (!boundsInBlocks) {
949 if (stride < frame_stride) return E_INVALIDARG;
950 if (bufferSize < frame_size) return E_INVALIDARG;
951 } else {
952 x = boundsInBlocks->X;
953 y = boundsInBlocks->Y;
954 width = boundsInBlocks->Width;
955 height = boundsInBlocks->Height;
956 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
957 x + width > This->info.width_in_blocks ||
958 y + height > This->info.height_in_blocks) {
959 return E_INVALIDARG;
961 if (stride < width * bytes_per_block) return E_INVALIDARG;
962 if (bufferSize < stride * height) return E_INVALIDARG;
965 return copy_pixels(This->info.bytes_per_block * 8, This->block_data, This->info.width_in_blocks,
966 This->info.height_in_blocks, frame_stride, boundsInBlocks, stride, bufferSize, buffer);
969 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = {
970 DdsFrameDecode_Dds_QueryInterface,
971 DdsFrameDecode_Dds_AddRef,
972 DdsFrameDecode_Dds_Release,
973 DdsFrameDecode_Dds_GetSizeInBlocks,
974 DdsFrameDecode_Dds_GetFormatInfo,
975 DdsFrameDecode_Dds_CopyBlocks
978 static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode)
980 DdsFrameDecode *result;
982 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
983 if (!result) return E_OUTOFMEMORY;
985 result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl;
986 result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl;
987 result->ref = 1;
988 InitializeCriticalSection(&result->lock);
989 result->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsFrameDecode.lock");
991 *frame_decode = result;
992 return S_OK;
995 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
996 void **ppv)
998 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
999 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1001 if (!ppv) return E_INVALIDARG;
1003 if (IsEqualIID(&IID_IUnknown, iid) ||
1004 IsEqualIID(&IID_IWICBitmapDecoder, iid)) {
1005 *ppv = &This->IWICBitmapDecoder_iface;
1006 } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) {
1007 *ppv = &This->IWICDdsDecoder_iface;
1008 } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) {
1009 *ppv = &This->IWICWineDecoder_iface;
1010 } else {
1011 *ppv = NULL;
1012 return E_NOINTERFACE;
1015 IUnknown_AddRef((IUnknown*)*ppv);
1016 return S_OK;
1019 static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface)
1021 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1022 ULONG ref = InterlockedIncrement(&This->ref);
1024 TRACE("(%p) refcount=%u\n", iface, ref);
1026 return ref;
1029 static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface)
1031 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1032 ULONG ref = InterlockedDecrement(&This->ref);
1034 TRACE("(%p) refcount=%u\n", iface, ref);
1036 if (ref == 0)
1038 This->lock.DebugInfo->Spare[0] = 0;
1039 DeleteCriticalSection(&This->lock);
1040 if (This->stream) IStream_Release(This->stream);
1041 HeapFree(GetProcessHeap(), 0, This);
1044 return ref;
1047 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1048 DWORD *capability)
1050 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
1052 return E_NOTIMPL;
1055 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1056 WICDecodeOptions cacheOptions)
1058 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1059 HRESULT hr;
1061 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1063 EnterCriticalSection(&This->lock);
1065 hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions);
1066 if (FAILED(hr)) goto end;
1068 if (This->info.dimension == WICDdsTextureCube ||
1069 (This->info.format != DXGI_FORMAT_BC1_UNORM &&
1070 This->info.format != DXGI_FORMAT_BC2_UNORM &&
1071 This->info.format != DXGI_FORMAT_BC3_UNORM)) {
1072 IStream_Release(pIStream);
1073 This->stream = NULL;
1074 This->initialized = FALSE;
1075 hr = WINCODEC_ERR_BADHEADER;
1078 end:
1079 LeaveCriticalSection(&This->lock);
1081 return hr;
1084 static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1085 GUID *pguidContainerFormat)
1087 TRACE("(%p,%p)\n", iface, pguidContainerFormat);
1089 memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID));
1091 return S_OK;
1094 static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1095 IWICBitmapDecoderInfo **ppIDecoderInfo)
1097 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1099 return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo);
1102 static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface,
1103 IWICPalette *pIPalette)
1105 TRACE("(%p,%p)\n", iface, pIPalette);
1107 return WINCODEC_ERR_PALETTEUNAVAILABLE;
1110 static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1111 IWICMetadataQueryReader **ppIMetadataQueryReader)
1113 if (!ppIMetadataQueryReader) return E_INVALIDARG;
1115 FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader);
1117 return E_NOTIMPL;
1120 static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface,
1121 IWICBitmapSource **ppIBitmapSource)
1123 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1125 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1128 static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1129 UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount)
1131 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount);
1133 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1136 static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1137 IWICBitmapSource **ppIThumbnail)
1139 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1141 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1144 static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1145 UINT *pCount)
1147 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1149 if (!pCount) return E_INVALIDARG;
1150 if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
1152 EnterCriticalSection(&This->lock);
1154 *pCount = This->info.frame_count;
1156 LeaveCriticalSection(&This->lock);
1158 TRACE("(%p) -> %d\n", iface, *pCount);
1160 return S_OK;
1163 static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface,
1164 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1166 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1167 UINT frame_per_texture, array_index, mip_level, slice_index, depth;
1169 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1171 if (!ppIBitmapFrame) return E_INVALIDARG;
1173 EnterCriticalSection(&This->lock);
1175 if (!This->initialized) {
1176 LeaveCriticalSection(&This->lock);
1177 return WINCODEC_ERR_WRONGSTATE;
1180 if (This->info.dimension == WICDdsTextureCube) {
1181 frame_per_texture = This->info.mip_levels;
1182 } else {
1183 frame_per_texture = This->info.frame_count / This->info.array_size;
1185 array_index = index / frame_per_texture;
1186 slice_index = index % frame_per_texture;
1187 depth = This->info.depth;
1188 mip_level = 0;
1189 while (slice_index >= depth)
1191 slice_index -= depth;
1192 mip_level++;
1193 if (depth > 1) depth /= 2;
1196 LeaveCriticalSection(&This->lock);
1198 return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame);
1201 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = {
1202 DdsDecoder_QueryInterface,
1203 DdsDecoder_AddRef,
1204 DdsDecoder_Release,
1205 DdsDecoder_QueryCapability,
1206 DdsDecoder_Initialize,
1207 DdsDecoder_GetContainerFormat,
1208 DdsDecoder_GetDecoderInfo,
1209 DdsDecoder_CopyPalette,
1210 DdsDecoder_GetMetadataQueryReader,
1211 DdsDecoder_GetPreview,
1212 DdsDecoder_GetColorContexts,
1213 DdsDecoder_GetThumbnail,
1214 DdsDecoder_GetFrameCount,
1215 DdsDecoder_GetFrame
1218 static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface,
1219 REFIID iid, void **ppv)
1221 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1222 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1225 static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface)
1227 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1228 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1231 static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface)
1233 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1234 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1237 static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface,
1238 WICDdsParameters *parameters)
1240 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1241 HRESULT hr;
1243 if (!parameters) return E_INVALIDARG;
1245 EnterCriticalSection(&This->lock);
1247 if (!This->initialized) {
1248 hr = WINCODEC_ERR_WRONGSTATE;
1249 goto end;
1252 parameters->Width = This->info.width;
1253 parameters->Height = This->info.height;
1254 parameters->Depth = This->info.depth;
1255 parameters->MipLevels = This->info.mip_levels;
1256 parameters->ArraySize = This->info.array_size;
1257 parameters->DxgiFormat = This->info.format;
1258 parameters->Dimension = This->info.dimension;
1259 parameters->AlphaMode = This->info.alpha_mode;
1261 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1262 iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1263 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1265 hr = S_OK;
1267 end:
1268 LeaveCriticalSection(&This->lock);
1270 return hr;
1273 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface,
1274 UINT arrayIndex, UINT mipLevel, UINT sliceIndex,
1275 IWICBitmapFrameDecode **bitmapFrame)
1277 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1278 HRESULT hr;
1279 LARGE_INTEGER seek;
1280 UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size;
1281 UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0;
1282 UINT bytes_per_block, bytesread, i;
1283 DdsFrameDecode *frame_decode = NULL;
1285 TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame);
1287 if (!bitmapFrame) return E_INVALIDARG;
1289 EnterCriticalSection(&This->lock);
1291 if (!This->initialized) {
1292 hr = WINCODEC_ERR_WRONGSTATE;
1293 goto end;
1296 if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) ||
1297 (arrayIndex >= This->info.array_size * 6) ||
1298 (mipLevel >= This->info.mip_levels) ||
1299 (sliceIndex >= This->info.depth)) {
1300 hr = E_INVALIDARG;
1301 goto end;
1304 if (is_compressed(This->info.format)) {
1305 block_width = DDS_BLOCK_WIDTH;
1306 block_height = DDS_BLOCK_HEIGHT;
1307 } else {
1308 block_width = 1;
1309 block_height = 1;
1311 bytes_per_block = This->info.bytes_per_block;
1312 seek.QuadPart = This->info.data_offset;
1314 width = This->info.width;
1315 height = This->info.height;
1316 depth = This->info.depth;
1317 for (i = 0; i < This->info.mip_levels; i++)
1319 width_in_blocks = (width + block_width - 1) / block_width;
1320 height_in_blocks = (height + block_height - 1) / block_height;
1321 size = width_in_blocks * height_in_blocks * bytes_per_block;
1323 if (i < mipLevel) {
1324 seek.QuadPart += size * depth;
1325 } else if (i == mipLevel){
1326 seek.QuadPart += size * sliceIndex;
1327 frame_width = width;
1328 frame_height = height;
1329 frame_width_in_blocks = width_in_blocks;
1330 frame_height_in_blocks = height_in_blocks;
1331 frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block;
1332 if (arrayIndex == 0) break;
1334 seek.QuadPart += arrayIndex * size * depth;
1336 if (width > 1) width /= 2;
1337 if (height > 1) height /= 2;
1338 if (depth > 1) depth /= 2;
1341 hr = DdsFrameDecode_CreateInstance(&frame_decode);
1342 if (hr != S_OK) goto end;
1343 frame_decode->info.width = frame_width;
1344 frame_decode->info.height = frame_height;
1345 frame_decode->info.format = This->info.format;
1346 frame_decode->info.bytes_per_block = bytes_per_block;
1347 frame_decode->info.block_width = block_width;
1348 frame_decode->info.block_height = block_height;
1349 frame_decode->info.width_in_blocks = frame_width_in_blocks;
1350 frame_decode->info.height_in_blocks = frame_height_in_blocks;
1351 frame_decode->info.pixel_format = This->info.pixel_format;
1352 frame_decode->info.pixel_format_bpp = This->info.pixel_format_bpp;
1353 frame_decode->block_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
1354 frame_decode->pixel_data = NULL;
1355 hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL);
1356 if (hr != S_OK) goto end;
1357 hr = IStream_Read(This->stream, frame_decode->block_data, frame_size, &bytesread);
1358 if (hr != S_OK || bytesread != frame_size) {
1359 hr = WINCODEC_ERR_STREAMREAD;
1360 goto end;
1362 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
1364 hr = S_OK;
1366 end:
1367 LeaveCriticalSection(&This->lock);
1369 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
1371 return hr;
1374 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = {
1375 DdsDecoder_Dds_QueryInterface,
1376 DdsDecoder_Dds_AddRef,
1377 DdsDecoder_Dds_Release,
1378 DdsDecoder_Dds_GetParameters,
1379 DdsDecoder_Dds_GetFrame
1382 static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv)
1384 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1385 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1388 static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface)
1390 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1391 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1394 static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface)
1396 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1397 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1400 static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options)
1402 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1403 DDS_HEADER_DXT10 header_dxt10;
1404 LARGE_INTEGER seek;
1405 DDS_HEADER header;
1406 ULONG bytesread;
1407 DWORD magic;
1408 HRESULT hr;
1410 TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options);
1412 EnterCriticalSection(&This->lock);
1414 if (This->initialized) {
1415 hr = WINCODEC_ERR_WRONGSTATE;
1416 goto end;
1419 seek.QuadPart = 0;
1420 hr = IStream_Seek(stream, seek, SEEK_SET, NULL);
1421 if (FAILED(hr)) goto end;
1423 hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread);
1424 if (FAILED(hr)) goto end;
1425 if (bytesread != sizeof(magic)) {
1426 hr = WINCODEC_ERR_STREAMREAD;
1427 goto end;
1429 if (magic != DDS_MAGIC) {
1430 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
1431 goto end;
1434 hr = IStream_Read(stream, &header, sizeof(header), &bytesread);
1435 if (FAILED(hr)) goto end;
1436 if (bytesread != sizeof(header)) {
1437 hr = WINCODEC_ERR_STREAMREAD;
1438 goto end;
1440 if (header.size != sizeof(header)) {
1441 hr = WINCODEC_ERR_BADHEADER;
1442 goto end;
1445 if (has_extended_header(&header)) {
1446 hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread);
1447 if (FAILED(hr)) goto end;
1448 if (bytesread != sizeof(header_dxt10)) {
1449 hr = WINCODEC_ERR_STREAMREAD;
1450 goto end;
1454 get_dds_info(&This->info, &header, &header_dxt10);
1456 This->initialized = TRUE;
1457 This->stream = stream;
1458 IStream_AddRef(stream);
1460 end:
1461 LeaveCriticalSection(&This->lock);
1463 return hr;
1466 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = {
1467 DdsDecoder_Wine_QueryInterface,
1468 DdsDecoder_Wine_AddRef,
1469 DdsDecoder_Wine_Release,
1470 DdsDecoder_Wine_Initialize
1473 HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv)
1475 DdsDecoder *This;
1476 HRESULT ret;
1478 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1480 *ppv = NULL;
1482 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder));
1483 if (!This) return E_OUTOFMEMORY;
1485 This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl;
1486 This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl;
1487 This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl;
1488 This->ref = 1;
1489 This->initialized = FALSE;
1490 This->stream = NULL;
1491 InitializeCriticalSection(&This->lock);
1492 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock");
1494 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1495 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1497 return ret;