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
22 * For uncompressed formats, a block is equivalent to a pixel.
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.
30 #include "wine/port.h"
40 #include "wincodecs_private.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
46 #define DDS_MAGIC 0x20534444
48 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
49 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
50 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
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
89 DWORD pitchOrLinearSize
;
93 DDS_PIXELFORMAT ddspf
;
103 DWORD resourceDimension
;
109 typedef struct dds_info
{
117 UINT bytes_per_block
; /* for uncompressed format, this means bytes per pixel*/
119 WICDdsDimension dimension
;
120 WICDdsAlphaMode alpha_mode
;
121 const GUID
*pixel_format
;
124 typedef struct dds_frame_info
{
128 UINT bytes_per_block
; /* for uncompressed format, this means bytes per pixel*/
131 UINT width_in_blocks
;
132 UINT height_in_blocks
;
133 const GUID
*pixel_format
;
136 typedef struct DdsDecoder
{
137 IWICBitmapDecoder IWICBitmapDecoder_iface
;
138 IWICDdsDecoder IWICDdsDecoder_iface
;
139 IWICWineDecoder IWICWineDecoder_iface
;
143 CRITICAL_SECTION lock
;
147 typedef struct DdsFrameDecode
{
148 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
149 IWICDdsFrameDecode IWICDdsFrameDecode_iface
;
155 static struct dds_format
{
156 DDS_PIXELFORMAT pixel_format
;
157 DXGI_FORMAT dxgi_format
;
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
)
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
;
229 if (header
->caps2
& DDSCAPS2_CUBEMAP
) {
230 return WICDdsTextureCube
;
231 } else if (header
->caps2
& DDSCAPS2_VOLUME
) {
232 return WICDdsTexture3D
;
234 return WICDdsTexture2D
;
239 static DXGI_FORMAT
get_dxgi_format(DDS_PIXELFORMAT
*pixel_format
)
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
)
262 case MAKEFOURCC('D', 'X', 'T', '1'):
263 case MAKEFOURCC('D', 'X', 'T', '2'):
264 case MAKEFOURCC('D', 'X', 'T', '4'):
265 return WICDdsAlphaModePremultiplied
;
267 return WICDdsAlphaModeUnknown
;
271 static UINT
get_bytes_per_block_from_format(DXGI_FORMAT format
)
273 /* for uncompressed format, return bytes per pixel*/
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
:
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
:
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
:
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
:
356 case DXGI_FORMAT_R32G32B32_TYPELESS
:
357 case DXGI_FORMAT_R32G32B32_FLOAT
:
358 case DXGI_FORMAT_R32G32B32_UINT
:
359 case DXGI_FORMAT_R32G32B32_SINT
:
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
:
382 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format
);
387 static BOOL
is_compressed(DXGI_FORMAT format
)
391 for (i
= 0; i
< ARRAY_SIZE(compressed_formats
); i
++)
393 if (format
== compressed_formats
[i
]) return TRUE
;
398 static void get_dds_info(dds_info
* info
, DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
403 info
->width
= header
->width
;
404 info
->height
= header
->height
;
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
);
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;
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
;
437 info
->frame_count
= 0;
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
,
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
;
490 return E_NOINTERFACE
;
493 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
515 HeapFree(GetProcessHeap(), 0, This
->data
);
516 HeapFree(GetProcessHeap(), 0, This
);
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
);
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
));
551 static HRESULT WINAPI
DdsFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
552 double *pDpiX
, double *pDpiY
)
554 FIXME("(%p,%p,%p): stub.\n", iface
, pDpiX
, pDpiY
);
559 static HRESULT WINAPI
DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
560 IWICPalette
*pIPalette
)
562 FIXME("(%p,%p): stub.\n", iface
, pIPalette
);
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
);
575 static HRESULT WINAPI
DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
576 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
578 FIXME("(%p,%p): stub.\n", iface
, ppIMetadataQueryReader
);
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
);
591 static HRESULT WINAPI
DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
592 IWICBitmapSource
**ppIThumbnail
)
594 FIXME("(%p,%p): stub.\n", iface
, ppIThumbnail
);
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
);
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
);
665 static HRESULT WINAPI
DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode
*iface
,
666 const WICRect
*boundsInBlocks
, UINT stride
, UINT bufferSize
,
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
);
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
) {
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
;
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
;
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
;
732 *frame_decode
= result
;
736 static HRESULT WINAPI
DdsDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
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
;
753 return E_NOINTERFACE
;
756 IUnknown_AddRef((IUnknown
*)*ppv
);
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
);
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
);
779 This
->lock
.DebugInfo
->Spare
[0] = 0;
780 DeleteCriticalSection(&This
->lock
);
781 if (This
->stream
) IStream_Release(This
->stream
);
782 HeapFree(GetProcessHeap(), 0, This
);
788 static HRESULT WINAPI
DdsDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
791 FIXME("(%p,%p,%p): stub.\n", iface
, stream
, capability
);
796 static HRESULT WINAPI
DdsDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
797 WICDecodeOptions cacheOptions
)
799 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
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
);
815 This
->initialized
= FALSE
;
816 hr
= WINCODEC_ERR_BADHEADER
;
820 LeaveCriticalSection(&This
->lock
);
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
));
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
);
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
,
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
);
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
;
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
;
930 while (slice_index
>= depth
)
932 slice_index
-= depth
;
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
,
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
,
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
);
984 if (!parameters
) return E_INVALIDARG
;
986 EnterCriticalSection(&This
->lock
);
988 if (!This
->initialized
) {
989 hr
= WINCODEC_ERR_WRONGSTATE
;
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
);
1009 LeaveCriticalSection(&This
->lock
);
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
);
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
;
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
)) {
1045 if (is_compressed(This
->info
.format
)) {
1046 block_width
= DDS_BLOCK_WIDTH
;
1047 block_height
= DDS_BLOCK_HEIGHT
;
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
;
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
;
1101 *bitmapFrame
= &frame_decode
->IWICBitmapFrameDecode_iface
;
1106 LeaveCriticalSection(&This
->lock
);
1108 if (hr
!= S_OK
&& frame_decode
) DdsFrameDecode_Release(&frame_decode
->IWICBitmapFrameDecode_iface
);
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
;
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
;
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
;
1168 if (magic
!= DDS_MAGIC
) {
1169 hr
= WINCODEC_ERR_UNKNOWNIMAGEFORMAT
;
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
;
1179 if (header
.size
!= sizeof(header
)) {
1180 hr
= WINCODEC_ERR_BADHEADER
;
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
;
1193 get_dds_info(&This
->info
, &header
, &header_dxt10
);
1195 This
->initialized
= TRUE
;
1196 This
->stream
= stream
;
1197 IStream_AddRef(stream
);
1200 LeaveCriticalSection(&This
->lock
);
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
)
1217 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
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
;
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
);