windowscodecs: In struct DdsFrameDecode, add a new member "pixel_data" and rename...
[wine.git] / dlls / windowscodecs / ddsformat.c
blobccd83ace55c73aee375f4a2bba5a09cd1ad02e0d
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 UINT pixel_format_bpp;
135 } dds_frame_info;
137 typedef struct DdsDecoder {
138 IWICBitmapDecoder IWICBitmapDecoder_iface;
139 IWICDdsDecoder IWICDdsDecoder_iface;
140 IWICWineDecoder IWICWineDecoder_iface;
141 LONG ref;
142 BOOL initialized;
143 IStream *stream;
144 CRITICAL_SECTION lock;
145 dds_info info;
146 } DdsDecoder;
148 typedef struct DdsFrameDecode {
149 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
150 IWICDdsFrameDecode IWICDdsFrameDecode_iface;
151 LONG ref;
152 BYTE *block_data;
153 BYTE *pixel_data;
154 CRITICAL_SECTION lock;
155 dds_frame_info info;
156 } DdsFrameDecode;
158 static struct dds_format {
159 DDS_PIXELFORMAT pixel_format;
160 DXGI_FORMAT dxgi_format;
161 } dds_formats[] = {
162 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC1_UNORM },
163 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC2_UNORM },
164 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC2_UNORM },
165 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC3_UNORM },
166 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC3_UNORM },
167 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_UNORM },
168 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_SNORM },
169 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_UNORM },
170 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_SNORM },
171 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC4_UNORM },
172 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_BC5_UNORM },
173 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_R8G8_B8G8_UNORM },
174 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_G8R8_G8B8_UNORM },
175 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 }, DXGI_FORMAT_UNKNOWN },
176 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_UNORM },
177 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_SNORM },
178 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16_FLOAT },
179 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16_FLOAT },
180 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R16G16B16A16_FLOAT },
181 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32_FLOAT },
182 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32G32_FLOAT },
183 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 }, DXGI_FORMAT_R32G32B32A32_FLOAT },
184 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 }, DXGI_FORMAT_R8G8B8A8_UNORM },
185 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 }, DXGI_FORMAT_B8G8R8A8_UNORM },
186 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 }, DXGI_FORMAT_B8G8R8X8_UNORM },
187 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
188 * For "correct" one, the RGB masks should be 0x3FF00000,0xFFC00,0x3FF.
189 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
190 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 }, DXGI_FORMAT_R10G10B10A2_UNORM },
191 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 }, DXGI_FORMAT_R16G16_UNORM },
192 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 }, DXGI_FORMAT_R32_FLOAT },
193 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 }, DXGI_FORMAT_B5G6R5_UNORM },
194 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 }, DXGI_FORMAT_B5G5R5A1_UNORM },
195 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 }, DXGI_FORMAT_B4G4R4A4_UNORM },
196 { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF }, DXGI_FORMAT_A8_UNORM },
197 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 }, DXGI_FORMAT_R16_UNORM },
198 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 }, DXGI_FORMAT_R8G8_UNORM },
199 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 }, DXGI_FORMAT_R8_UNORM }
202 static DXGI_FORMAT compressed_formats[] = {
203 DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB,
204 DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB,
205 DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB,
206 DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM,
207 DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM,
208 DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16,
209 DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB
212 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **);
214 static inline BOOL has_extended_header(DDS_HEADER *header)
216 return (header->ddspf.flags & DDPF_FOURCC) &&
217 (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'));
220 static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
222 if (header_dxt10) {
223 if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube;
224 switch (header_dxt10->resourceDimension)
226 case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D;
227 case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D;
228 case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D;
229 default: return WICDdsTexture2D;
231 } else {
232 if (header->caps2 & DDSCAPS2_CUBEMAP) {
233 return WICDdsTextureCube;
234 } else if (header->caps2 & DDSCAPS2_VOLUME) {
235 return WICDdsTexture3D;
236 } else {
237 return WICDdsTexture2D;
242 static DXGI_FORMAT get_dxgi_format(DDS_PIXELFORMAT *pixel_format)
244 UINT i;
246 for (i = 0; i < ARRAY_SIZE(dds_formats); i++)
248 if ((pixel_format->flags & dds_formats[i].pixel_format.flags) &&
249 (pixel_format->fourCC == dds_formats[i].pixel_format.fourCC) &&
250 (pixel_format->rgbBitCount == dds_formats[i].pixel_format.rgbBitCount) &&
251 (pixel_format->rBitMask == dds_formats[i].pixel_format.rBitMask) &&
252 (pixel_format->gBitMask == dds_formats[i].pixel_format.gBitMask) &&
253 (pixel_format->bBitMask == dds_formats[i].pixel_format.bBitMask) &&
254 (pixel_format->aBitMask == dds_formats[i].pixel_format.aBitMask))
255 return dds_formats[i].dxgi_format;
258 return DXGI_FORMAT_UNKNOWN;
261 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
263 switch (fourcc)
265 case MAKEFOURCC('D', 'X', 'T', '1'):
266 case MAKEFOURCC('D', 'X', 'T', '2'):
267 case MAKEFOURCC('D', 'X', 'T', '4'):
268 return WICDdsAlphaModePremultiplied;
269 default:
270 return WICDdsAlphaModeUnknown;
274 static UINT get_bytes_per_block_from_format(DXGI_FORMAT format)
276 /* for uncompressed format, return bytes per pixel*/
277 switch (format)
279 case DXGI_FORMAT_R8_TYPELESS:
280 case DXGI_FORMAT_R8_UNORM:
281 case DXGI_FORMAT_R8_UINT:
282 case DXGI_FORMAT_R8_SNORM:
283 case DXGI_FORMAT_R8_SINT:
284 case DXGI_FORMAT_A8_UNORM:
285 return 1;
286 case DXGI_FORMAT_R8G8_TYPELESS:
287 case DXGI_FORMAT_R8G8_UNORM:
288 case DXGI_FORMAT_R8G8_UINT:
289 case DXGI_FORMAT_R8G8_SNORM:
290 case DXGI_FORMAT_R8G8_SINT:
291 case DXGI_FORMAT_R16_TYPELESS:
292 case DXGI_FORMAT_R16_FLOAT:
293 case DXGI_FORMAT_D16_UNORM:
294 case DXGI_FORMAT_R16_UNORM:
295 case DXGI_FORMAT_R16_UINT:
296 case DXGI_FORMAT_R16_SNORM:
297 case DXGI_FORMAT_R16_SINT:
298 case DXGI_FORMAT_B5G6R5_UNORM:
299 case DXGI_FORMAT_B5G5R5A1_UNORM:
300 case DXGI_FORMAT_B4G4R4A4_UNORM:
301 return 2;
302 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
303 case DXGI_FORMAT_R10G10B10A2_UNORM:
304 case DXGI_FORMAT_R10G10B10A2_UINT:
305 case DXGI_FORMAT_R11G11B10_FLOAT:
306 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
307 case DXGI_FORMAT_R8G8B8A8_UNORM:
308 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
309 case DXGI_FORMAT_R8G8B8A8_UINT:
310 case DXGI_FORMAT_R8G8B8A8_SNORM:
311 case DXGI_FORMAT_R8G8B8A8_SINT:
312 case DXGI_FORMAT_R16G16_TYPELESS:
313 case DXGI_FORMAT_R16G16_FLOAT:
314 case DXGI_FORMAT_R16G16_UNORM:
315 case DXGI_FORMAT_R16G16_UINT:
316 case DXGI_FORMAT_R16G16_SNORM:
317 case DXGI_FORMAT_R16G16_SINT:
318 case DXGI_FORMAT_R32_TYPELESS:
319 case DXGI_FORMAT_D32_FLOAT:
320 case DXGI_FORMAT_R32_FLOAT:
321 case DXGI_FORMAT_R32_UINT:
322 case DXGI_FORMAT_R32_SINT:
323 case DXGI_FORMAT_R24G8_TYPELESS:
324 case DXGI_FORMAT_D24_UNORM_S8_UINT:
325 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
326 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
327 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
328 case DXGI_FORMAT_R8G8_B8G8_UNORM:
329 case DXGI_FORMAT_G8R8_G8B8_UNORM:
330 case DXGI_FORMAT_B8G8R8A8_UNORM:
331 case DXGI_FORMAT_B8G8R8X8_UNORM:
332 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
333 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
334 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
335 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
336 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
337 return 4;
338 case DXGI_FORMAT_BC1_UNORM:
339 case DXGI_FORMAT_BC1_TYPELESS:
340 case DXGI_FORMAT_BC1_UNORM_SRGB:
341 case DXGI_FORMAT_BC4_TYPELESS:
342 case DXGI_FORMAT_BC4_UNORM:
343 case DXGI_FORMAT_BC4_SNORM:
344 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
345 case DXGI_FORMAT_R16G16B16A16_FLOAT:
346 case DXGI_FORMAT_R16G16B16A16_UNORM:
347 case DXGI_FORMAT_R16G16B16A16_UINT:
348 case DXGI_FORMAT_R16G16B16A16_SNORM:
349 case DXGI_FORMAT_R16G16B16A16_SINT:
350 case DXGI_FORMAT_R32G32_TYPELESS:
351 case DXGI_FORMAT_R32G32_FLOAT:
352 case DXGI_FORMAT_R32G32_UINT:
353 case DXGI_FORMAT_R32G32_SINT:
354 case DXGI_FORMAT_R32G8X24_TYPELESS:
355 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
356 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
357 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
358 return 8;
359 case DXGI_FORMAT_R32G32B32_TYPELESS:
360 case DXGI_FORMAT_R32G32B32_FLOAT:
361 case DXGI_FORMAT_R32G32B32_UINT:
362 case DXGI_FORMAT_R32G32B32_SINT:
363 return 12;
364 case DXGI_FORMAT_BC2_UNORM:
365 case DXGI_FORMAT_BC2_TYPELESS:
366 case DXGI_FORMAT_BC2_UNORM_SRGB:
367 case DXGI_FORMAT_BC3_UNORM:
368 case DXGI_FORMAT_BC3_TYPELESS:
369 case DXGI_FORMAT_BC3_UNORM_SRGB:
370 case DXGI_FORMAT_BC5_TYPELESS:
371 case DXGI_FORMAT_BC5_UNORM:
372 case DXGI_FORMAT_BC5_SNORM:
373 case DXGI_FORMAT_BC6H_TYPELESS:
374 case DXGI_FORMAT_BC6H_UF16:
375 case DXGI_FORMAT_BC6H_SF16:
376 case DXGI_FORMAT_BC7_TYPELESS:
377 case DXGI_FORMAT_BC7_UNORM:
378 case DXGI_FORMAT_BC7_UNORM_SRGB:
379 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
380 case DXGI_FORMAT_R32G32B32A32_FLOAT:
381 case DXGI_FORMAT_R32G32B32A32_UINT:
382 case DXGI_FORMAT_R32G32B32A32_SINT:
383 return 16;
384 default:
385 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
386 return 0;
390 static BOOL is_compressed(DXGI_FORMAT format)
392 UINT i;
394 for (i = 0; i < ARRAY_SIZE(compressed_formats); i++)
396 if (format == compressed_formats[i]) return TRUE;
398 return FALSE;
401 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
403 int i;
404 UINT depth;
406 info->width = header->width;
407 info->height = header->height;
408 info->depth = 1;
409 info->mip_levels = 1;
410 info->array_size = 1;
411 if (header->depth) info->depth = header->depth;
412 if (header->mipMapCount) info->mip_levels = header->mipMapCount;
414 if (has_extended_header(header)) {
415 if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize;
416 info->format = header_dxt10->dxgiFormat;
417 info->dimension = get_dimension(NULL, header_dxt10);
418 info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008;
419 info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10);
420 } else {
421 info->format = get_dxgi_format(&header->ddspf);
422 info->dimension = get_dimension(header, NULL);
423 info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC);
424 info->data_offset = sizeof(DWORD) + sizeof(*header);
426 info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ?
427 &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA;
429 if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) {
430 info->bytes_per_block = header->ddspf.rgbBitCount / 8;
431 } else {
432 info->bytes_per_block = get_bytes_per_block_from_format(info->format);
435 /* get frame count */
437 if (info->depth == 1) {
438 info->frame_count = info->array_size * info->mip_levels;
439 } else {
440 info->frame_count = 0;
441 depth = info->depth;
442 for (i = 0; i < info->mip_levels; i++)
444 info->frame_count += depth;
445 if (depth > 1) depth /= 2;
447 info->frame_count *= info->array_size;
449 if (info->dimension == WICDdsTextureCube) info->frame_count *= 6;
452 static UINT get_pixel_format_bpp(const GUID *pixel_format)
454 HRESULT hr;
455 UINT bpp = 0;
456 IWICComponentInfo *info = NULL;
457 IWICPixelFormatInfo* format_info = NULL;
459 hr = CreateComponentInfo(pixel_format, &info);
460 if (hr != S_OK) goto end;
461 hr = IWICComponentInfo_QueryInterface(info, &IID_IWICPixelFormatInfo, (void **)&format_info);
462 if (hr != S_OK) goto end;
464 IWICPixelFormatInfo_GetBitsPerPixel(format_info, &bpp);
466 end:
467 if (format_info) IWICPixelFormatInfo_Release(format_info);
468 if (info) IWICComponentInfo_Release(info);
470 return bpp;
473 static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
475 return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface);
478 static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface)
480 return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface);
483 static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface)
485 return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface);
488 static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
490 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface);
493 static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface)
495 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface);
498 static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
499 void **ppv)
501 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
502 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
504 if (!ppv) return E_INVALIDARG;
506 if (IsEqualIID(&IID_IUnknown, iid) ||
507 IsEqualIID(&IID_IWICBitmapSource, iid) ||
508 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) {
509 *ppv = &This->IWICBitmapFrameDecode_iface;
510 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) {
511 *ppv = &This->IWICDdsFrameDecode_iface;
512 } else {
513 *ppv = NULL;
514 return E_NOINTERFACE;
517 IUnknown_AddRef((IUnknown*)*ppv);
518 return S_OK;
521 static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
523 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
524 ULONG ref = InterlockedIncrement(&This->ref);
526 TRACE("(%p) refcount=%u\n", iface, ref);
528 return ref;
531 static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface)
533 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
534 ULONG ref = InterlockedDecrement(&This->ref);
536 TRACE("(%p) refcount=%u\n", iface, ref);
538 if (ref == 0) {
539 HeapFree(GetProcessHeap(), 0, This->pixel_data);
540 HeapFree(GetProcessHeap(), 0, This->block_data);
541 HeapFree(GetProcessHeap(), 0, This);
544 return ref;
547 static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
548 UINT *puiWidth, UINT *puiHeight)
550 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
552 if (!puiWidth || !puiHeight) return E_INVALIDARG;
554 *puiWidth = This->info.width;
555 *puiHeight = This->info.height;
557 TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight);
559 return S_OK;
562 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
563 WICPixelFormatGUID *pPixelFormat)
565 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
567 if (!pPixelFormat) return E_INVALIDARG;
569 *pPixelFormat = *This->info.pixel_format;
571 TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat));
573 return S_OK;
576 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
577 double *pDpiX, double *pDpiY)
579 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
581 return E_NOTIMPL;
584 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
585 IWICPalette *pIPalette)
587 FIXME("(%p,%p): stub.\n", iface, pIPalette);
589 return E_NOTIMPL;
592 static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
593 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
595 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
596 UINT bpp, frame_stride, frame_size;
597 INT x, y, width, height;
598 HRESULT hr = S_OK;
600 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
602 if (!pbBuffer) return E_INVALIDARG;
604 bpp = This->info.pixel_format_bpp;
605 frame_stride = This->info.width * bpp / 8;
606 frame_size = frame_stride * This->info.height;
607 if (!prc) {
608 if (cbStride < frame_stride) return E_INVALIDARG;
609 if (cbBufferSize < frame_size) return WINCODEC_ERR_INSUFFICIENTBUFFER;
610 return S_OK;
613 x = prc->X;
614 y = prc->Y;
615 width = prc->Width;
616 height = prc->Height;
617 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
618 x + width > This->info.width ||
619 y + height > This->info.height) {
620 return E_INVALIDARG;
622 if (cbStride < width * bpp / 8) return E_INVALIDARG;
623 if (cbBufferSize < cbStride * height) return WINCODEC_ERR_INSUFFICIENTBUFFER;
625 EnterCriticalSection(&This->lock);
627 if (!This->pixel_data) {
628 This->pixel_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
629 if (!This->pixel_data) {
630 hr = E_OUTOFMEMORY;
631 goto end;
635 end:
636 LeaveCriticalSection(&This->lock);
638 return hr;
641 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
642 IWICMetadataQueryReader **ppIMetadataQueryReader)
644 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
646 return E_NOTIMPL;
649 static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
650 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
652 FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount);
654 return E_NOTIMPL;
657 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
658 IWICBitmapSource **ppIThumbnail)
660 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
662 return E_NOTIMPL;
665 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = {
666 DdsFrameDecode_QueryInterface,
667 DdsFrameDecode_AddRef,
668 DdsFrameDecode_Release,
669 DdsFrameDecode_GetSize,
670 DdsFrameDecode_GetPixelFormat,
671 DdsFrameDecode_GetResolution,
672 DdsFrameDecode_CopyPalette,
673 DdsFrameDecode_CopyPixels,
674 DdsFrameDecode_GetMetadataQueryReader,
675 DdsFrameDecode_GetColorContexts,
676 DdsFrameDecode_GetThumbnail
679 static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface,
680 REFIID iid, void **ppv)
682 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
683 return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
686 static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface)
688 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
689 return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
692 static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface)
694 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
695 return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
698 static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface,
699 UINT *widthInBlocks, UINT *heightInBlocks)
701 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
703 if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG;
705 *widthInBlocks = This->info.width_in_blocks;
706 *heightInBlocks = This->info.height_in_blocks;
708 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks);
710 return S_OK;
713 static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface,
714 WICDdsFormatInfo *formatInfo)
716 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
718 if (!formatInfo) return E_INVALIDARG;
720 formatInfo->DxgiFormat = This->info.format;
721 formatInfo->BytesPerBlock = This->info.bytes_per_block;
722 formatInfo->BlockWidth = This->info.block_width;
723 formatInfo->BlockHeight = This->info.block_height;
725 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo,
726 formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight);
728 return S_OK;
731 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
732 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
733 BYTE *buffer)
735 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
736 int x, y, width, height;
737 UINT bytes_per_block, frame_stride, frame_size, i;
738 BYTE *data, *dst_buffer;
740 TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer);
742 if (!buffer) return E_INVALIDARG;
744 bytes_per_block = This->info.bytes_per_block;
745 frame_stride = This->info.width_in_blocks * bytes_per_block;
746 frame_size = frame_stride * This->info.height_in_blocks;
747 if (!boundsInBlocks) {
748 if (stride < frame_stride) return E_INVALIDARG;
749 if (bufferSize < frame_size) return E_INVALIDARG;
750 memcpy(buffer, This->block_data, frame_size);
751 return S_OK;
754 x = boundsInBlocks->X;
755 y = boundsInBlocks->Y;
756 width = boundsInBlocks->Width;
757 height = boundsInBlocks->Height;
758 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
759 x + width > This->info.width_in_blocks ||
760 y + height > This->info.height_in_blocks) {
761 return E_INVALIDARG;
763 if (stride < width * bytes_per_block) return E_INVALIDARG;
764 if (bufferSize < stride * height) return E_INVALIDARG;
766 data = This->block_data + (x + y * This->info.width_in_blocks) * bytes_per_block;
767 dst_buffer = buffer;
768 for (i = 0; i < height; i++)
770 memcpy(dst_buffer, data, (size_t)width * bytes_per_block);
771 data += This->info.width_in_blocks * bytes_per_block;
772 dst_buffer += stride;
775 return S_OK;
778 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = {
779 DdsFrameDecode_Dds_QueryInterface,
780 DdsFrameDecode_Dds_AddRef,
781 DdsFrameDecode_Dds_Release,
782 DdsFrameDecode_Dds_GetSizeInBlocks,
783 DdsFrameDecode_Dds_GetFormatInfo,
784 DdsFrameDecode_Dds_CopyBlocks
787 static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode)
789 DdsFrameDecode *result;
791 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
792 if (!result) return E_OUTOFMEMORY;
794 result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl;
795 result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl;
796 result->ref = 1;
797 InitializeCriticalSection(&result->lock);
798 result->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsFrameDecode.lock");
800 *frame_decode = result;
801 return S_OK;
804 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
805 void **ppv)
807 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
808 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
810 if (!ppv) return E_INVALIDARG;
812 if (IsEqualIID(&IID_IUnknown, iid) ||
813 IsEqualIID(&IID_IWICBitmapDecoder, iid)) {
814 *ppv = &This->IWICBitmapDecoder_iface;
815 } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) {
816 *ppv = &This->IWICDdsDecoder_iface;
817 } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) {
818 *ppv = &This->IWICWineDecoder_iface;
819 } else {
820 *ppv = NULL;
821 return E_NOINTERFACE;
824 IUnknown_AddRef((IUnknown*)*ppv);
825 return S_OK;
828 static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface)
830 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
831 ULONG ref = InterlockedIncrement(&This->ref);
833 TRACE("(%p) refcount=%u\n", iface, ref);
835 return ref;
838 static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface)
840 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
841 ULONG ref = InterlockedDecrement(&This->ref);
843 TRACE("(%p) refcount=%u\n", iface, ref);
845 if (ref == 0)
847 This->lock.DebugInfo->Spare[0] = 0;
848 DeleteCriticalSection(&This->lock);
849 if (This->stream) IStream_Release(This->stream);
850 HeapFree(GetProcessHeap(), 0, This);
853 return ref;
856 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
857 DWORD *capability)
859 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
861 return E_NOTIMPL;
864 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
865 WICDecodeOptions cacheOptions)
867 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
868 HRESULT hr;
870 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
872 EnterCriticalSection(&This->lock);
874 hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions);
875 if (FAILED(hr)) goto end;
877 if (This->info.dimension == WICDdsTextureCube ||
878 (This->info.format != DXGI_FORMAT_BC1_UNORM &&
879 This->info.format != DXGI_FORMAT_BC2_UNORM &&
880 This->info.format != DXGI_FORMAT_BC3_UNORM)) {
881 IStream_Release(pIStream);
882 This->stream = NULL;
883 This->initialized = FALSE;
884 hr = WINCODEC_ERR_BADHEADER;
887 end:
888 LeaveCriticalSection(&This->lock);
890 return hr;
893 static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
894 GUID *pguidContainerFormat)
896 TRACE("(%p,%p)\n", iface, pguidContainerFormat);
898 memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID));
900 return S_OK;
903 static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
904 IWICBitmapDecoderInfo **ppIDecoderInfo)
906 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
908 return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo);
911 static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface,
912 IWICPalette *pIPalette)
914 TRACE("(%p,%p)\n", iface, pIPalette);
916 return WINCODEC_ERR_PALETTEUNAVAILABLE;
919 static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
920 IWICMetadataQueryReader **ppIMetadataQueryReader)
922 if (!ppIMetadataQueryReader) return E_INVALIDARG;
924 FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader);
926 return E_NOTIMPL;
929 static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface,
930 IWICBitmapSource **ppIBitmapSource)
932 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
934 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
937 static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface,
938 UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount)
940 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount);
942 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
945 static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface,
946 IWICBitmapSource **ppIThumbnail)
948 TRACE("(%p,%p)\n", iface, ppIThumbnail);
950 return WINCODEC_ERR_CODECNOTHUMBNAIL;
953 static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface,
954 UINT *pCount)
956 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
958 if (!pCount) return E_INVALIDARG;
959 if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
961 EnterCriticalSection(&This->lock);
963 *pCount = This->info.frame_count;
965 LeaveCriticalSection(&This->lock);
967 TRACE("(%p) -> %d\n", iface, *pCount);
969 return S_OK;
972 static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface,
973 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
975 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
976 UINT frame_per_texture, array_index, mip_level, slice_index, depth;
978 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
980 if (!ppIBitmapFrame) return E_INVALIDARG;
982 EnterCriticalSection(&This->lock);
984 if (!This->initialized) {
985 LeaveCriticalSection(&This->lock);
986 return WINCODEC_ERR_WRONGSTATE;
989 if (This->info.dimension == WICDdsTextureCube) {
990 frame_per_texture = This->info.mip_levels;
991 } else {
992 frame_per_texture = This->info.frame_count / This->info.array_size;
994 array_index = index / frame_per_texture;
995 slice_index = index % frame_per_texture;
996 depth = This->info.depth;
997 mip_level = 0;
998 while (slice_index >= depth)
1000 slice_index -= depth;
1001 mip_level++;
1002 if (depth > 1) depth /= 2;
1005 LeaveCriticalSection(&This->lock);
1007 return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame);
1010 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = {
1011 DdsDecoder_QueryInterface,
1012 DdsDecoder_AddRef,
1013 DdsDecoder_Release,
1014 DdsDecoder_QueryCapability,
1015 DdsDecoder_Initialize,
1016 DdsDecoder_GetContainerFormat,
1017 DdsDecoder_GetDecoderInfo,
1018 DdsDecoder_CopyPalette,
1019 DdsDecoder_GetMetadataQueryReader,
1020 DdsDecoder_GetPreview,
1021 DdsDecoder_GetColorContexts,
1022 DdsDecoder_GetThumbnail,
1023 DdsDecoder_GetFrameCount,
1024 DdsDecoder_GetFrame
1027 static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface,
1028 REFIID iid, void **ppv)
1030 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1031 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1034 static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface)
1036 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1037 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1040 static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface)
1042 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1043 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1046 static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface,
1047 WICDdsParameters *parameters)
1049 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1050 HRESULT hr;
1052 if (!parameters) return E_INVALIDARG;
1054 EnterCriticalSection(&This->lock);
1056 if (!This->initialized) {
1057 hr = WINCODEC_ERR_WRONGSTATE;
1058 goto end;
1061 parameters->Width = This->info.width;
1062 parameters->Height = This->info.height;
1063 parameters->Depth = This->info.depth;
1064 parameters->MipLevels = This->info.mip_levels;
1065 parameters->ArraySize = This->info.array_size;
1066 parameters->DxgiFormat = This->info.format;
1067 parameters->Dimension = This->info.dimension;
1068 parameters->AlphaMode = This->info.alpha_mode;
1070 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1071 iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1072 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1074 hr = S_OK;
1076 end:
1077 LeaveCriticalSection(&This->lock);
1079 return hr;
1082 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface,
1083 UINT arrayIndex, UINT mipLevel, UINT sliceIndex,
1084 IWICBitmapFrameDecode **bitmapFrame)
1086 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1087 HRESULT hr;
1088 LARGE_INTEGER seek;
1089 UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size;
1090 UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0;
1091 UINT bytes_per_block, bytesread, i;
1092 DdsFrameDecode *frame_decode = NULL;
1094 TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame);
1096 if (!bitmapFrame) return E_INVALIDARG;
1098 EnterCriticalSection(&This->lock);
1100 if (!This->initialized) {
1101 hr = WINCODEC_ERR_WRONGSTATE;
1102 goto end;
1105 if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) ||
1106 (arrayIndex >= This->info.array_size * 6) ||
1107 (mipLevel >= This->info.mip_levels) ||
1108 (sliceIndex >= This->info.depth)) {
1109 hr = E_INVALIDARG;
1110 goto end;
1113 if (is_compressed(This->info.format)) {
1114 block_width = DDS_BLOCK_WIDTH;
1115 block_height = DDS_BLOCK_HEIGHT;
1116 } else {
1117 block_width = 1;
1118 block_height = 1;
1120 bytes_per_block = This->info.bytes_per_block;
1121 seek.QuadPart = This->info.data_offset;
1123 width = This->info.width;
1124 height = This->info.height;
1125 depth = This->info.depth;
1126 for (i = 0; i < This->info.mip_levels; i++)
1128 width_in_blocks = (width + block_width - 1) / block_width;
1129 height_in_blocks = (height + block_height - 1) / block_height;
1130 size = width_in_blocks * height_in_blocks * bytes_per_block;
1132 if (i < mipLevel) {
1133 seek.QuadPart += size * depth;
1134 } else if (i == mipLevel){
1135 seek.QuadPart += size * sliceIndex;
1136 frame_width = width;
1137 frame_height = height;
1138 frame_width_in_blocks = width_in_blocks;
1139 frame_height_in_blocks = height_in_blocks;
1140 frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block;
1141 if (arrayIndex == 0) break;
1143 seek.QuadPart += arrayIndex * size * depth;
1145 if (width > 1) width /= 2;
1146 if (height > 1) height /= 2;
1147 if (depth > 1) depth /= 2;
1150 hr = DdsFrameDecode_CreateInstance(&frame_decode);
1151 if (hr != S_OK) goto end;
1152 frame_decode->info.width = frame_width;
1153 frame_decode->info.height = frame_height;
1154 frame_decode->info.format = This->info.format;
1155 frame_decode->info.bytes_per_block = bytes_per_block;
1156 frame_decode->info.block_width = block_width;
1157 frame_decode->info.block_height = block_height;
1158 frame_decode->info.width_in_blocks = frame_width_in_blocks;
1159 frame_decode->info.height_in_blocks = frame_height_in_blocks;
1160 frame_decode->info.pixel_format = This->info.pixel_format;
1161 frame_decode->info.pixel_format_bpp = get_pixel_format_bpp(This->info.pixel_format);
1162 frame_decode->block_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
1163 frame_decode->pixel_data = NULL;
1164 hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL);
1165 if (hr != S_OK) goto end;
1166 hr = IStream_Read(This->stream, frame_decode->block_data, frame_size, &bytesread);
1167 if (hr != S_OK || bytesread != frame_size) {
1168 hr = WINCODEC_ERR_STREAMREAD;
1169 goto end;
1171 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
1173 hr = S_OK;
1175 end:
1176 LeaveCriticalSection(&This->lock);
1178 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
1180 return hr;
1183 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = {
1184 DdsDecoder_Dds_QueryInterface,
1185 DdsDecoder_Dds_AddRef,
1186 DdsDecoder_Dds_Release,
1187 DdsDecoder_Dds_GetParameters,
1188 DdsDecoder_Dds_GetFrame
1191 static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv)
1193 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1194 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1197 static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface)
1199 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1200 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1203 static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface)
1205 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1206 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1209 static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options)
1211 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1212 DDS_HEADER_DXT10 header_dxt10;
1213 LARGE_INTEGER seek;
1214 DDS_HEADER header;
1215 ULONG bytesread;
1216 DWORD magic;
1217 HRESULT hr;
1219 TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options);
1221 EnterCriticalSection(&This->lock);
1223 if (This->initialized) {
1224 hr = WINCODEC_ERR_WRONGSTATE;
1225 goto end;
1228 seek.QuadPart = 0;
1229 hr = IStream_Seek(stream, seek, SEEK_SET, NULL);
1230 if (FAILED(hr)) goto end;
1232 hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread);
1233 if (FAILED(hr)) goto end;
1234 if (bytesread != sizeof(magic)) {
1235 hr = WINCODEC_ERR_STREAMREAD;
1236 goto end;
1238 if (magic != DDS_MAGIC) {
1239 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
1240 goto end;
1243 hr = IStream_Read(stream, &header, sizeof(header), &bytesread);
1244 if (FAILED(hr)) goto end;
1245 if (bytesread != sizeof(header)) {
1246 hr = WINCODEC_ERR_STREAMREAD;
1247 goto end;
1249 if (header.size != sizeof(header)) {
1250 hr = WINCODEC_ERR_BADHEADER;
1251 goto end;
1254 if (has_extended_header(&header)) {
1255 hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread);
1256 if (FAILED(hr)) goto end;
1257 if (bytesread != sizeof(header_dxt10)) {
1258 hr = WINCODEC_ERR_STREAMREAD;
1259 goto end;
1263 get_dds_info(&This->info, &header, &header_dxt10);
1265 This->initialized = TRUE;
1266 This->stream = stream;
1267 IStream_AddRef(stream);
1269 end:
1270 LeaveCriticalSection(&This->lock);
1272 return hr;
1275 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = {
1276 DdsDecoder_Wine_QueryInterface,
1277 DdsDecoder_Wine_AddRef,
1278 DdsDecoder_Wine_Release,
1279 DdsDecoder_Wine_Initialize
1282 HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv)
1284 DdsDecoder *This;
1285 HRESULT ret;
1287 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1289 *ppv = NULL;
1291 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder));
1292 if (!This) return E_OUTOFMEMORY;
1294 This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl;
1295 This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl;
1296 This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl;
1297 This->ref = 1;
1298 This->initialized = FALSE;
1299 This->stream = NULL;
1300 InitializeCriticalSection(&This->lock);
1301 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock");
1303 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1304 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1306 return ret;