windowscodecs: Fix alpha mode of DXT3 and DXT5 image.
[wine.git] / dlls / windowscodecs / ddsformat.c
blob87cbf4df9122e923b3894c92c014015cfa87d352
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 DDPF_ALPHAPIXELS 0x00000001
54 #define DDPF_ALPHA 0x00000002
55 #define DDPF_FOURCC 0x00000004
56 #define DDPF_PALETTEINDEXED8 0x00000020
57 #define DDPF_RGB 0x00000040
58 #define DDPF_LUMINANCE 0x00020000
59 #define DDPF_BUMPDUDV 0x00080000
61 #define DDSCAPS2_CUBEMAP 0x00000200
62 #define DDSCAPS2_VOLUME 0x00200000
64 #define DDS_DIMENSION_TEXTURE1D 2
65 #define DDS_DIMENSION_TEXTURE2D 3
66 #define DDS_DIMENSION_TEXTURE3D 4
68 #define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004
70 #define DDS_BLOCK_WIDTH 4
71 #define DDS_BLOCK_HEIGHT 4
73 typedef struct {
74 DWORD size;
75 DWORD flags;
76 DWORD fourCC;
77 DWORD rgbBitCount;
78 DWORD rBitMask;
79 DWORD gBitMask;
80 DWORD bBitMask;
81 DWORD aBitMask;
82 } DDS_PIXELFORMAT;
84 typedef struct {
85 DWORD size;
86 DWORD flags;
87 DWORD height;
88 DWORD width;
89 DWORD pitchOrLinearSize;
90 DWORD depth;
91 DWORD mipMapCount;
92 DWORD reserved1[11];
93 DDS_PIXELFORMAT ddspf;
94 DWORD caps;
95 DWORD caps2;
96 DWORD caps3;
97 DWORD caps4;
98 DWORD reserved2;
99 } DDS_HEADER;
101 typedef struct {
102 DWORD dxgiFormat;
103 DWORD resourceDimension;
104 DWORD miscFlag;
105 DWORD arraySize;
106 DWORD miscFlags2;
107 } DDS_HEADER_DXT10;
109 typedef struct dds_info {
110 UINT width;
111 UINT height;
112 UINT depth;
113 UINT mip_levels;
114 UINT array_size;
115 UINT frame_count;
116 UINT data_offset;
117 UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/
118 DXGI_FORMAT format;
119 WICDdsDimension dimension;
120 WICDdsAlphaMode alpha_mode;
121 const GUID *pixel_format;
122 } dds_info;
124 typedef struct dds_frame_info {
125 UINT width;
126 UINT height;
127 DXGI_FORMAT format;
128 UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/
129 UINT block_width;
130 UINT block_height;
131 UINT width_in_blocks;
132 UINT height_in_blocks;
133 const GUID *pixel_format;
134 } dds_frame_info;
136 typedef struct DdsDecoder {
137 IWICBitmapDecoder IWICBitmapDecoder_iface;
138 IWICDdsDecoder IWICDdsDecoder_iface;
139 IWICWineDecoder IWICWineDecoder_iface;
140 LONG ref;
141 BOOL initialized;
142 IStream *stream;
143 CRITICAL_SECTION lock;
144 dds_info info;
145 } DdsDecoder;
147 typedef struct DdsFrameDecode {
148 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
149 IWICDdsFrameDecode IWICDdsFrameDecode_iface;
150 LONG ref;
151 BYTE *data;
152 dds_frame_info info;
153 } DdsFrameDecode;
155 static struct dds_format {
156 DDS_PIXELFORMAT pixel_format;
157 DXGI_FORMAT dxgi_format;
158 } dds_formats[] = {
159 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC1_UNORM },
160 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC2_UNORM },
161 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC2_UNORM },
162 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC3_UNORM },
163 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC3_UNORM },
164 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_UNORM },
165 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_SNORM },
166 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_UNORM },
167 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_SNORM },
168 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_UNORM },
169 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_UNORM },
170 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_R8G8_B8G8_UNORM },
171 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_G8R8_G8B8_UNORM },
172 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_UNKNOWN },
173 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_UNORM },
174 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_SNORM },
175 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16_FLOAT },
176 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16_FLOAT },
177 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_FLOAT },
178 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32_FLOAT },
179 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32G32_FLOAT },
180 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32G32B32A32_FLOAT },
181 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 }, DXGI_FORMAT_R8G8B8A8_UNORM },
182 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 }, DXGI_FORMAT_B8G8R8A8_UNORM },
183 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 }, DXGI_FORMAT_B8G8R8X8_UNORM },
184 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
185 * For "correct" one, the RGB masks should be 0x3FF00000,0xFFC00,0x3FF.
186 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
187 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 }, DXGI_FORMAT_R10G10B10A2_UNORM },
188 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 }, DXGI_FORMAT_R16G16_UNORM },
189 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 }, DXGI_FORMAT_R32_FLOAT },
190 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 }, DXGI_FORMAT_B5G6R5_UNORM },
191 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 }, DXGI_FORMAT_B5G5R5A1_UNORM },
192 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 }, DXGI_FORMAT_B4G4R4A4_UNORM },
193 { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF }, DXGI_FORMAT_A8_UNORM },
194 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 }, DXGI_FORMAT_R16_UNORM },
195 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 }, DXGI_FORMAT_R8G8_UNORM },
196 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 }, DXGI_FORMAT_R8_UNORM }
199 static DXGI_FORMAT compressed_formats[] = {
200 DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB,
201 DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB,
202 DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB,
203 DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM,
204 DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM,
205 DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16,
206 DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB
209 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **);
211 static inline BOOL has_extended_header(DDS_HEADER *header)
213 return (header->ddspf.flags & DDPF_FOURCC) &&
214 (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'));
217 static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
219 if (header_dxt10) {
220 if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube;
221 switch (header_dxt10->resourceDimension)
223 case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D;
224 case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D;
225 case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D;
226 default: return WICDdsTexture2D;
228 } else {
229 if (header->caps2 & DDSCAPS2_CUBEMAP) {
230 return WICDdsTextureCube;
231 } else if (header->caps2 & DDSCAPS2_VOLUME) {
232 return WICDdsTexture3D;
233 } else {
234 return WICDdsTexture2D;
239 static DXGI_FORMAT get_dxgi_format(DDS_PIXELFORMAT *pixel_format)
241 UINT i;
243 for (i = 0; i < ARRAY_SIZE(dds_formats); i++)
245 if ((pixel_format->flags & dds_formats[i].pixel_format.flags) &&
246 (pixel_format->fourCC == dds_formats[i].pixel_format.fourCC) &&
247 (pixel_format->rgbBitCount == dds_formats[i].pixel_format.rgbBitCount) &&
248 (pixel_format->rBitMask == dds_formats[i].pixel_format.rBitMask) &&
249 (pixel_format->gBitMask == dds_formats[i].pixel_format.gBitMask) &&
250 (pixel_format->bBitMask == dds_formats[i].pixel_format.bBitMask) &&
251 (pixel_format->aBitMask == dds_formats[i].pixel_format.aBitMask))
252 return dds_formats[i].dxgi_format;
255 return DXGI_FORMAT_UNKNOWN;
258 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
260 switch (fourcc)
262 case MAKEFOURCC('D', 'X', 'T', '1'):
263 case MAKEFOURCC('D', 'X', 'T', '2'):
264 case MAKEFOURCC('D', 'X', 'T', '4'):
265 return WICDdsAlphaModePremultiplied;
266 default:
267 return WICDdsAlphaModeUnknown;
271 static UINT get_bytes_per_block_from_format(DXGI_FORMAT format)
273 /* for uncompressed format, return bytes per pixel*/
274 switch (format)
276 case DXGI_FORMAT_R8_TYPELESS:
277 case DXGI_FORMAT_R8_UNORM:
278 case DXGI_FORMAT_R8_UINT:
279 case DXGI_FORMAT_R8_SNORM:
280 case DXGI_FORMAT_R8_SINT:
281 case DXGI_FORMAT_A8_UNORM:
282 return 1;
283 case DXGI_FORMAT_R8G8_TYPELESS:
284 case DXGI_FORMAT_R8G8_UNORM:
285 case DXGI_FORMAT_R8G8_UINT:
286 case DXGI_FORMAT_R8G8_SNORM:
287 case DXGI_FORMAT_R8G8_SINT:
288 case DXGI_FORMAT_R16_TYPELESS:
289 case DXGI_FORMAT_R16_FLOAT:
290 case DXGI_FORMAT_D16_UNORM:
291 case DXGI_FORMAT_R16_UNORM:
292 case DXGI_FORMAT_R16_UINT:
293 case DXGI_FORMAT_R16_SNORM:
294 case DXGI_FORMAT_R16_SINT:
295 case DXGI_FORMAT_B5G6R5_UNORM:
296 case DXGI_FORMAT_B5G5R5A1_UNORM:
297 case DXGI_FORMAT_B4G4R4A4_UNORM:
298 return 2;
299 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
300 case DXGI_FORMAT_R10G10B10A2_UNORM:
301 case DXGI_FORMAT_R10G10B10A2_UINT:
302 case DXGI_FORMAT_R11G11B10_FLOAT:
303 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
304 case DXGI_FORMAT_R8G8B8A8_UNORM:
305 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
306 case DXGI_FORMAT_R8G8B8A8_UINT:
307 case DXGI_FORMAT_R8G8B8A8_SNORM:
308 case DXGI_FORMAT_R8G8B8A8_SINT:
309 case DXGI_FORMAT_R16G16_TYPELESS:
310 case DXGI_FORMAT_R16G16_FLOAT:
311 case DXGI_FORMAT_R16G16_UNORM:
312 case DXGI_FORMAT_R16G16_UINT:
313 case DXGI_FORMAT_R16G16_SNORM:
314 case DXGI_FORMAT_R16G16_SINT:
315 case DXGI_FORMAT_R32_TYPELESS:
316 case DXGI_FORMAT_D32_FLOAT:
317 case DXGI_FORMAT_R32_FLOAT:
318 case DXGI_FORMAT_R32_UINT:
319 case DXGI_FORMAT_R32_SINT:
320 case DXGI_FORMAT_R24G8_TYPELESS:
321 case DXGI_FORMAT_D24_UNORM_S8_UINT:
322 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
323 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
324 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
325 case DXGI_FORMAT_R8G8_B8G8_UNORM:
326 case DXGI_FORMAT_G8R8_G8B8_UNORM:
327 case DXGI_FORMAT_B8G8R8A8_UNORM:
328 case DXGI_FORMAT_B8G8R8X8_UNORM:
329 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
330 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
331 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
332 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
333 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
334 return 4;
335 case DXGI_FORMAT_BC1_UNORM:
336 case DXGI_FORMAT_BC1_TYPELESS:
337 case DXGI_FORMAT_BC1_UNORM_SRGB:
338 case DXGI_FORMAT_BC4_TYPELESS:
339 case DXGI_FORMAT_BC4_UNORM:
340 case DXGI_FORMAT_BC4_SNORM:
341 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
342 case DXGI_FORMAT_R16G16B16A16_FLOAT:
343 case DXGI_FORMAT_R16G16B16A16_UNORM:
344 case DXGI_FORMAT_R16G16B16A16_UINT:
345 case DXGI_FORMAT_R16G16B16A16_SNORM:
346 case DXGI_FORMAT_R16G16B16A16_SINT:
347 case DXGI_FORMAT_R32G32_TYPELESS:
348 case DXGI_FORMAT_R32G32_FLOAT:
349 case DXGI_FORMAT_R32G32_UINT:
350 case DXGI_FORMAT_R32G32_SINT:
351 case DXGI_FORMAT_R32G8X24_TYPELESS:
352 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
353 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
354 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
355 return 8;
356 case DXGI_FORMAT_R32G32B32_TYPELESS:
357 case DXGI_FORMAT_R32G32B32_FLOAT:
358 case DXGI_FORMAT_R32G32B32_UINT:
359 case DXGI_FORMAT_R32G32B32_SINT:
360 return 12;
361 case DXGI_FORMAT_BC2_UNORM:
362 case DXGI_FORMAT_BC2_TYPELESS:
363 case DXGI_FORMAT_BC2_UNORM_SRGB:
364 case DXGI_FORMAT_BC3_UNORM:
365 case DXGI_FORMAT_BC3_TYPELESS:
366 case DXGI_FORMAT_BC3_UNORM_SRGB:
367 case DXGI_FORMAT_BC5_TYPELESS:
368 case DXGI_FORMAT_BC5_UNORM:
369 case DXGI_FORMAT_BC5_SNORM:
370 case DXGI_FORMAT_BC6H_TYPELESS:
371 case DXGI_FORMAT_BC6H_UF16:
372 case DXGI_FORMAT_BC6H_SF16:
373 case DXGI_FORMAT_BC7_TYPELESS:
374 case DXGI_FORMAT_BC7_UNORM:
375 case DXGI_FORMAT_BC7_UNORM_SRGB:
376 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
377 case DXGI_FORMAT_R32G32B32A32_FLOAT:
378 case DXGI_FORMAT_R32G32B32A32_UINT:
379 case DXGI_FORMAT_R32G32B32A32_SINT:
380 return 16;
381 default:
382 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
383 return 0;
387 static BOOL is_compressed(DXGI_FORMAT format)
389 UINT i;
391 for (i = 0; i < ARRAY_SIZE(compressed_formats); i++)
393 if (format == compressed_formats[i]) return TRUE;
395 return FALSE;
398 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
400 int i;
401 UINT depth;
403 info->width = header->width;
404 info->height = header->height;
405 info->depth = 1;
406 info->mip_levels = 1;
407 info->array_size = 1;
408 if (header->depth) info->depth = header->depth;
409 if (header->mipMapCount) info->mip_levels = header->mipMapCount;
411 if (has_extended_header(header)) {
412 if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize;
413 info->format = header_dxt10->dxgiFormat;
414 info->dimension = get_dimension(NULL, header_dxt10);
415 info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008;
416 info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10);
417 } else {
418 info->format = get_dxgi_format(&header->ddspf);
419 info->dimension = get_dimension(header, NULL);
420 info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC);
421 info->data_offset = sizeof(DWORD) + sizeof(*header);
423 info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ?
424 &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA;
426 if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) {
427 info->bytes_per_block = header->ddspf.rgbBitCount / 8;
428 } else {
429 info->bytes_per_block = get_bytes_per_block_from_format(info->format);
432 /* get frame count */
434 if (info->depth == 1) {
435 info->frame_count = info->array_size * info->mip_levels;
436 } else {
437 info->frame_count = 0;
438 depth = info->depth;
439 for (i = 0; i < info->mip_levels; i++)
441 info->frame_count += depth;
442 if (depth > 1) depth /= 2;
444 info->frame_count *= info->array_size;
446 if (info->dimension == WICDdsTextureCube) info->frame_count *= 6;
449 static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
451 return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface);
454 static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface)
456 return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface);
459 static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface)
461 return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface);
464 static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
466 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface);
469 static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface)
471 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface);
474 static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
475 void **ppv)
477 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
478 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
480 if (!ppv) return E_INVALIDARG;
482 if (IsEqualIID(&IID_IUnknown, iid) ||
483 IsEqualIID(&IID_IWICBitmapSource, iid) ||
484 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) {
485 *ppv = &This->IWICBitmapFrameDecode_iface;
486 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) {
487 *ppv = &This->IWICDdsFrameDecode_iface;
488 } else {
489 *ppv = NULL;
490 return E_NOINTERFACE;
493 IUnknown_AddRef((IUnknown*)*ppv);
494 return S_OK;
497 static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
499 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
500 ULONG ref = InterlockedIncrement(&This->ref);
502 TRACE("(%p) refcount=%u\n", iface, ref);
504 return ref;
507 static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface)
509 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
510 ULONG ref = InterlockedDecrement(&This->ref);
512 TRACE("(%p) refcount=%u\n", iface, ref);
514 if (ref == 0) {
515 HeapFree(GetProcessHeap(), 0, This->data);
516 HeapFree(GetProcessHeap(), 0, This);
519 return ref;
522 static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
523 UINT *puiWidth, UINT *puiHeight)
525 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
527 if (!puiWidth || !puiHeight) return E_INVALIDARG;
529 *puiWidth = This->info.width;
530 *puiHeight = This->info.height;
532 TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight);
534 return S_OK;
537 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
538 WICPixelFormatGUID *pPixelFormat)
540 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
542 if (!pPixelFormat) return E_INVALIDARG;
544 *pPixelFormat = *This->info.pixel_format;
546 TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat));
548 return S_OK;
551 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
552 double *pDpiX, double *pDpiY)
554 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
556 return E_NOTIMPL;
559 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
560 IWICPalette *pIPalette)
562 FIXME("(%p,%p): stub.\n", iface, pIPalette);
564 return E_NOTIMPL;
567 static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
568 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
570 FIXME("(%p,%s,%u,%u,%p): stub.\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
572 return E_NOTIMPL;
575 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
576 IWICMetadataQueryReader **ppIMetadataQueryReader)
578 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
580 return E_NOTIMPL;
583 static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
584 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
586 FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount);
588 return E_NOTIMPL;
591 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
592 IWICBitmapSource **ppIThumbnail)
594 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
596 return E_NOTIMPL;
599 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = {
600 DdsFrameDecode_QueryInterface,
601 DdsFrameDecode_AddRef,
602 DdsFrameDecode_Release,
603 DdsFrameDecode_GetSize,
604 DdsFrameDecode_GetPixelFormat,
605 DdsFrameDecode_GetResolution,
606 DdsFrameDecode_CopyPalette,
607 DdsFrameDecode_CopyPixels,
608 DdsFrameDecode_GetMetadataQueryReader,
609 DdsFrameDecode_GetColorContexts,
610 DdsFrameDecode_GetThumbnail
613 static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface,
614 REFIID iid, void **ppv)
616 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
617 return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
620 static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface)
622 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
623 return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
626 static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface)
628 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
629 return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
632 static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface,
633 UINT *widthInBlocks, UINT *heightInBlocks)
635 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
637 if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG;
639 *widthInBlocks = This->info.width_in_blocks;
640 *heightInBlocks = This->info.height_in_blocks;
642 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks);
644 return S_OK;
647 static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface,
648 WICDdsFormatInfo *formatInfo)
650 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
652 if (!formatInfo) return E_INVALIDARG;
654 formatInfo->DxgiFormat = This->info.format;
655 formatInfo->BytesPerBlock = This->info.bytes_per_block;
656 formatInfo->BlockWidth = This->info.block_width;
657 formatInfo->BlockHeight = This->info.block_height;
659 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo,
660 formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight);
662 return S_OK;
665 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
666 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
667 BYTE *buffer)
669 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
670 int x, y, width, height;
671 UINT bytes_per_block, frame_stride, frame_size, i;
672 BYTE *data, *dst_buffer;
674 TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer);
676 if (!buffer) return E_INVALIDARG;
678 bytes_per_block = This->info.bytes_per_block;
679 frame_stride = This->info.width_in_blocks * bytes_per_block;
680 frame_size = frame_stride * This->info.height_in_blocks;
681 if (!boundsInBlocks) {
682 if (stride < frame_stride) return E_INVALIDARG;
683 if (bufferSize < frame_size) return E_INVALIDARG;
684 memcpy(buffer, This->data, frame_size);
685 return S_OK;
688 x = boundsInBlocks->X;
689 y = boundsInBlocks->Y;
690 width = boundsInBlocks->Width;
691 height = boundsInBlocks->Height;
692 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
693 x + width > This->info.width_in_blocks ||
694 y + height > This->info.height_in_blocks) {
695 return E_INVALIDARG;
697 if (stride < width * bytes_per_block) return E_INVALIDARG;
698 if (bufferSize < stride * height) return E_INVALIDARG;
700 data = This->data + (x + y * This->info.width_in_blocks) * bytes_per_block;
701 dst_buffer = buffer;
702 for (i = 0; i < height; i++)
704 memcpy(dst_buffer, data, (size_t)width * bytes_per_block);
705 data += This->info.width_in_blocks * bytes_per_block;
706 dst_buffer += stride;
709 return S_OK;
712 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = {
713 DdsFrameDecode_Dds_QueryInterface,
714 DdsFrameDecode_Dds_AddRef,
715 DdsFrameDecode_Dds_Release,
716 DdsFrameDecode_Dds_GetSizeInBlocks,
717 DdsFrameDecode_Dds_GetFormatInfo,
718 DdsFrameDecode_Dds_CopyBlocks
721 static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode)
723 DdsFrameDecode *result;
725 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
726 if (!result) return E_OUTOFMEMORY;
728 result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl;
729 result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl;
730 result->ref = 1;
732 *frame_decode = result;
733 return S_OK;
736 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
737 void **ppv)
739 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
740 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
742 if (!ppv) return E_INVALIDARG;
744 if (IsEqualIID(&IID_IUnknown, iid) ||
745 IsEqualIID(&IID_IWICBitmapDecoder, iid)) {
746 *ppv = &This->IWICBitmapDecoder_iface;
747 } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) {
748 *ppv = &This->IWICDdsDecoder_iface;
749 } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) {
750 *ppv = &This->IWICWineDecoder_iface;
751 } else {
752 *ppv = NULL;
753 return E_NOINTERFACE;
756 IUnknown_AddRef((IUnknown*)*ppv);
757 return S_OK;
760 static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface)
762 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
763 ULONG ref = InterlockedIncrement(&This->ref);
765 TRACE("(%p) refcount=%u\n", iface, ref);
767 return ref;
770 static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface)
772 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
773 ULONG ref = InterlockedDecrement(&This->ref);
775 TRACE("(%p) refcount=%u\n", iface, ref);
777 if (ref == 0)
779 This->lock.DebugInfo->Spare[0] = 0;
780 DeleteCriticalSection(&This->lock);
781 if (This->stream) IStream_Release(This->stream);
782 HeapFree(GetProcessHeap(), 0, This);
785 return ref;
788 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
789 DWORD *capability)
791 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
793 return E_NOTIMPL;
796 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
797 WICDecodeOptions cacheOptions)
799 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
800 HRESULT hr;
802 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
804 EnterCriticalSection(&This->lock);
806 hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions);
807 if (FAILED(hr)) goto end;
809 if (This->info.dimension == WICDdsTextureCube ||
810 (This->info.format != DXGI_FORMAT_BC1_UNORM &&
811 This->info.format != DXGI_FORMAT_BC2_UNORM &&
812 This->info.format != DXGI_FORMAT_BC3_UNORM)) {
813 IStream_Release(pIStream);
814 This->stream = NULL;
815 This->initialized = FALSE;
816 hr = WINCODEC_ERR_BADHEADER;
819 end:
820 LeaveCriticalSection(&This->lock);
822 return hr;
825 static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
826 GUID *pguidContainerFormat)
828 TRACE("(%p,%p)\n", iface, pguidContainerFormat);
830 memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID));
832 return S_OK;
835 static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
836 IWICBitmapDecoderInfo **ppIDecoderInfo)
838 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
840 return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo);
843 static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface,
844 IWICPalette *pIPalette)
846 TRACE("(%p,%p)\n", iface, pIPalette);
848 return WINCODEC_ERR_PALETTEUNAVAILABLE;
851 static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
852 IWICMetadataQueryReader **ppIMetadataQueryReader)
854 if (!ppIMetadataQueryReader) return E_INVALIDARG;
856 FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader);
858 return E_NOTIMPL;
861 static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface,
862 IWICBitmapSource **ppIBitmapSource)
864 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
866 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
869 static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface,
870 UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount)
872 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount);
874 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
877 static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface,
878 IWICBitmapSource **ppIThumbnail)
880 TRACE("(%p,%p)\n", iface, ppIThumbnail);
882 return WINCODEC_ERR_CODECNOTHUMBNAIL;
885 static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface,
886 UINT *pCount)
888 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
890 if (!pCount) return E_INVALIDARG;
891 if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
893 EnterCriticalSection(&This->lock);
895 *pCount = This->info.frame_count;
897 LeaveCriticalSection(&This->lock);
899 TRACE("(%p) -> %d\n", iface, *pCount);
901 return S_OK;
904 static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface,
905 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
907 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
908 UINT frame_per_texture, array_index, mip_level, slice_index, depth;
910 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
912 if (!ppIBitmapFrame) return E_INVALIDARG;
914 EnterCriticalSection(&This->lock);
916 if (!This->initialized) {
917 LeaveCriticalSection(&This->lock);
918 return WINCODEC_ERR_WRONGSTATE;
921 if (This->info.dimension == WICDdsTextureCube) {
922 frame_per_texture = This->info.mip_levels;
923 } else {
924 frame_per_texture = This->info.frame_count / This->info.array_size;
926 array_index = index / frame_per_texture;
927 slice_index = index % frame_per_texture;
928 depth = This->info.depth;
929 mip_level = 0;
930 while (slice_index >= depth)
932 slice_index -= depth;
933 mip_level++;
934 if (depth > 1) depth /= 2;
937 LeaveCriticalSection(&This->lock);
939 return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame);
942 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = {
943 DdsDecoder_QueryInterface,
944 DdsDecoder_AddRef,
945 DdsDecoder_Release,
946 DdsDecoder_QueryCapability,
947 DdsDecoder_Initialize,
948 DdsDecoder_GetContainerFormat,
949 DdsDecoder_GetDecoderInfo,
950 DdsDecoder_CopyPalette,
951 DdsDecoder_GetMetadataQueryReader,
952 DdsDecoder_GetPreview,
953 DdsDecoder_GetColorContexts,
954 DdsDecoder_GetThumbnail,
955 DdsDecoder_GetFrameCount,
956 DdsDecoder_GetFrame
959 static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface,
960 REFIID iid, void **ppv)
962 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
963 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
966 static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface)
968 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
969 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
972 static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface)
974 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
975 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
978 static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface,
979 WICDdsParameters *parameters)
981 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
982 HRESULT hr;
984 if (!parameters) return E_INVALIDARG;
986 EnterCriticalSection(&This->lock);
988 if (!This->initialized) {
989 hr = WINCODEC_ERR_WRONGSTATE;
990 goto end;
993 parameters->Width = This->info.width;
994 parameters->Height = This->info.height;
995 parameters->Depth = This->info.depth;
996 parameters->MipLevels = This->info.mip_levels;
997 parameters->ArraySize = This->info.array_size;
998 parameters->DxgiFormat = This->info.format;
999 parameters->Dimension = This->info.dimension;
1000 parameters->AlphaMode = This->info.alpha_mode;
1002 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1003 iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1004 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1006 hr = S_OK;
1008 end:
1009 LeaveCriticalSection(&This->lock);
1011 return hr;
1014 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface,
1015 UINT arrayIndex, UINT mipLevel, UINT sliceIndex,
1016 IWICBitmapFrameDecode **bitmapFrame)
1018 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1019 HRESULT hr;
1020 LARGE_INTEGER seek;
1021 UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size;
1022 UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0;
1023 UINT bytes_per_block, bytesread, i;
1024 DdsFrameDecode *frame_decode = NULL;
1026 TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame);
1028 if (!bitmapFrame) return E_INVALIDARG;
1030 EnterCriticalSection(&This->lock);
1032 if (!This->initialized) {
1033 hr = WINCODEC_ERR_WRONGSTATE;
1034 goto end;
1037 if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) ||
1038 (arrayIndex >= This->info.array_size * 6) ||
1039 (mipLevel >= This->info.mip_levels) ||
1040 (sliceIndex >= This->info.depth)) {
1041 hr = E_INVALIDARG;
1042 goto end;
1045 if (is_compressed(This->info.format)) {
1046 block_width = DDS_BLOCK_WIDTH;
1047 block_height = DDS_BLOCK_HEIGHT;
1048 } else {
1049 block_width = 1;
1050 block_height = 1;
1052 bytes_per_block = This->info.bytes_per_block;
1053 seek.QuadPart = This->info.data_offset;
1055 width = This->info.width;
1056 height = This->info.height;
1057 depth = This->info.depth;
1058 for (i = 0; i < This->info.mip_levels; i++)
1060 width_in_blocks = (width + block_width - 1) / block_width;
1061 height_in_blocks = (height + block_height - 1) / block_height;
1062 size = width_in_blocks * height_in_blocks * bytes_per_block;
1064 if (i < mipLevel) {
1065 seek.QuadPart += size * depth;
1066 } else if (i == mipLevel){
1067 seek.QuadPart += size * sliceIndex;
1068 frame_width = width;
1069 frame_height = height;
1070 frame_width_in_blocks = width_in_blocks;
1071 frame_height_in_blocks = height_in_blocks;
1072 frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block;
1073 if (arrayIndex == 0) break;
1075 seek.QuadPart += arrayIndex * size * depth;
1077 if (width > 1) width /= 2;
1078 if (height > 1) height /= 2;
1079 if (depth > 1) depth /= 2;
1082 hr = DdsFrameDecode_CreateInstance(&frame_decode);
1083 if (hr != S_OK) goto end;
1084 frame_decode->info.width = frame_width;
1085 frame_decode->info.height = frame_height;
1086 frame_decode->info.format = This->info.format;
1087 frame_decode->info.bytes_per_block = bytes_per_block;
1088 frame_decode->info.block_width = block_width;
1089 frame_decode->info.block_height = block_height;
1090 frame_decode->info.width_in_blocks = frame_width_in_blocks;
1091 frame_decode->info.height_in_blocks = frame_height_in_blocks;
1092 frame_decode->info.pixel_format = This->info.pixel_format;
1093 frame_decode->data = HeapAlloc(GetProcessHeap(), 0, frame_size);
1094 hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL);
1095 if (hr != S_OK) goto end;
1096 hr = IStream_Read(This->stream, frame_decode->data, frame_size, &bytesread);
1097 if (hr != S_OK || bytesread != frame_size) {
1098 hr = WINCODEC_ERR_STREAMREAD;
1099 goto end;
1101 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
1103 hr = S_OK;
1105 end:
1106 LeaveCriticalSection(&This->lock);
1108 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
1110 return hr;
1113 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = {
1114 DdsDecoder_Dds_QueryInterface,
1115 DdsDecoder_Dds_AddRef,
1116 DdsDecoder_Dds_Release,
1117 DdsDecoder_Dds_GetParameters,
1118 DdsDecoder_Dds_GetFrame
1121 static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv)
1123 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1124 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1127 static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface)
1129 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1130 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1133 static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface)
1135 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1136 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1139 static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options)
1141 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1142 DDS_HEADER_DXT10 header_dxt10;
1143 LARGE_INTEGER seek;
1144 DDS_HEADER header;
1145 ULONG bytesread;
1146 DWORD magic;
1147 HRESULT hr;
1149 TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options);
1151 EnterCriticalSection(&This->lock);
1153 if (This->initialized) {
1154 hr = WINCODEC_ERR_WRONGSTATE;
1155 goto end;
1158 seek.QuadPart = 0;
1159 hr = IStream_Seek(stream, seek, SEEK_SET, NULL);
1160 if (FAILED(hr)) goto end;
1162 hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread);
1163 if (FAILED(hr)) goto end;
1164 if (bytesread != sizeof(magic)) {
1165 hr = WINCODEC_ERR_STREAMREAD;
1166 goto end;
1168 if (magic != DDS_MAGIC) {
1169 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
1170 goto end;
1173 hr = IStream_Read(stream, &header, sizeof(header), &bytesread);
1174 if (FAILED(hr)) goto end;
1175 if (bytesread != sizeof(header)) {
1176 hr = WINCODEC_ERR_STREAMREAD;
1177 goto end;
1179 if (header.size != sizeof(header)) {
1180 hr = WINCODEC_ERR_BADHEADER;
1181 goto end;
1184 if (has_extended_header(&header)) {
1185 hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread);
1186 if (FAILED(hr)) goto end;
1187 if (bytesread != sizeof(header_dxt10)) {
1188 hr = WINCODEC_ERR_STREAMREAD;
1189 goto end;
1193 get_dds_info(&This->info, &header, &header_dxt10);
1195 This->initialized = TRUE;
1196 This->stream = stream;
1197 IStream_AddRef(stream);
1199 end:
1200 LeaveCriticalSection(&This->lock);
1202 return hr;
1205 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = {
1206 DdsDecoder_Wine_QueryInterface,
1207 DdsDecoder_Wine_AddRef,
1208 DdsDecoder_Wine_Release,
1209 DdsDecoder_Wine_Initialize
1212 HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv)
1214 DdsDecoder *This;
1215 HRESULT ret;
1217 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1219 *ppv = NULL;
1221 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder));
1222 if (!This) return E_OUTOFMEMORY;
1224 This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl;
1225 This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl;
1226 This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl;
1227 This->ref = 1;
1228 This->initialized = FALSE;
1229 This->stream = NULL;
1230 InitializeCriticalSection(&This->lock);
1231 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock");
1233 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1234 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1236 return ret;