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
20 #include "wine/port.h"
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
36 #define DDS_MAGIC 0x20534444
38 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
39 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
40 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
43 #define DDPF_ALPHAPIXELS 0x00000001
44 #define DDPF_ALPHA 0x00000002
45 #define DDPF_FOURCC 0x00000004
46 #define DDPF_PALETTEINDEXED8 0x00000020
47 #define DDPF_RGB 0x00000040
48 #define DDPF_LUMINANCE 0x00020000
49 #define DDPF_BUMPDUDV 0x00080000
51 #define DDSCAPS2_CUBEMAP 0x00000200
52 #define DDSCAPS2_VOLUME 0x00200000
54 #define DDS_DIMENSION_TEXTURE1D 2
55 #define DDS_DIMENSION_TEXTURE2D 3
56 #define DDS_DIMENSION_TEXTURE3D 4
58 #define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004
60 #define DDS_BLOCK_WIDTH 4
61 #define DDS_BLOCK_HEIGHT 4
79 DWORD pitchOrLinearSize
;
83 DDS_PIXELFORMAT ddspf
;
93 DWORD resourceDimension
;
99 typedef struct dds_info
{
107 WICDdsDimension dimension
;
108 WICDdsAlphaMode alpha_mode
;
111 typedef struct dds_frame_info
{
115 UINT bytes_per_block
;
118 UINT width_in_blocks
;
119 UINT height_in_blocks
;
122 typedef struct DdsDecoder
{
123 IWICBitmapDecoder IWICBitmapDecoder_iface
;
124 IWICDdsDecoder IWICDdsDecoder_iface
;
128 CRITICAL_SECTION lock
;
130 DDS_HEADER_DXT10 header_dxt10
;
134 typedef struct DdsFrameDecode
{
135 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
136 IWICDdsFrameDecode IWICDdsFrameDecode_iface
;
142 static HRESULT WINAPI
DdsDecoder_Dds_GetFrame(IWICDdsDecoder
*, UINT
, UINT
, UINT
, IWICBitmapFrameDecode
**);
144 static inline BOOL
has_extended_header(DDS_HEADER
*header
)
146 return (header
->ddspf
.flags
& DDPF_FOURCC
) &&
147 (header
->ddspf
.fourCC
== MAKEFOURCC('D', 'X', '1', '0'));
150 static WICDdsDimension
get_dimension(DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
153 if (header_dxt10
->miscFlag
& DDS_RESOURCE_MISC_TEXTURECUBE
) return WICDdsTextureCube
;
154 switch (header_dxt10
->resourceDimension
)
156 case DDS_DIMENSION_TEXTURE1D
: return WICDdsTexture1D
;
157 case DDS_DIMENSION_TEXTURE2D
: return WICDdsTexture2D
;
158 case DDS_DIMENSION_TEXTURE3D
: return WICDdsTexture3D
;
159 default: return WICDdsTexture2D
;
162 if (header
->caps2
& DDSCAPS2_CUBEMAP
) {
163 return WICDdsTextureCube
;
164 } else if (header
->caps2
& DDSCAPS2_VOLUME
) {
165 return WICDdsTexture3D
;
167 return WICDdsTexture2D
;
172 static DXGI_FORMAT
get_format_from_fourcc(DWORD fourcc
)
176 case MAKEFOURCC('D', 'X', 'T', '1'):
177 return DXGI_FORMAT_BC1_UNORM
;
178 case MAKEFOURCC('D', 'X', 'T', '2'):
179 case MAKEFOURCC('D', 'X', 'T', '3'):
180 return DXGI_FORMAT_BC2_UNORM
;
181 case MAKEFOURCC('D', 'X', 'T', '4'):
182 case MAKEFOURCC('D', 'X', 'T', '5'):
183 return DXGI_FORMAT_BC3_UNORM
;
184 case MAKEFOURCC('D', 'X', '1', '0'):
185 /* format is indicated in extended header */
186 return DXGI_FORMAT_UNKNOWN
;
188 /* there are DDS files where fourCC is set directly to DXGI_FORMAT enumeration value */
193 static WICDdsAlphaMode
get_alpha_mode_from_fourcc(DWORD fourcc
)
197 case MAKEFOURCC('D', 'X', 'T', '1'):
198 case MAKEFOURCC('D', 'X', 'T', '2'):
199 case MAKEFOURCC('D', 'X', 'T', '4'):
200 return WICDdsAlphaModePremultiplied
;
201 case MAKEFOURCC('D', 'X', 'T', '3'):
202 case MAKEFOURCC('D', 'X', 'T', '5'):
203 return WICDdsAlphaModeStraight
;
205 return WICDdsAlphaModeUnknown
;
209 static void get_dds_info(dds_info
* info
, DDS_HEADER
*header
, DDS_HEADER_DXT10
*header_dxt10
)
214 info
->width
= header
->width
;
215 info
->height
= header
->height
;
217 info
->mip_levels
= 1;
218 info
->array_size
= 1;
219 if (header
->depth
) info
->depth
= header
->depth
;
220 if (header
->mipMapCount
) info
->mip_levels
= header
->mipMapCount
;
222 if (has_extended_header(header
)) {
223 if (header_dxt10
->arraySize
) info
->array_size
= header_dxt10
->arraySize
;
224 info
->format
= header_dxt10
->dxgiFormat
;
225 info
->dimension
= get_dimension(NULL
, header_dxt10
);
226 info
->alpha_mode
= header_dxt10
->miscFlags2
& 0x00000008;
228 info
->format
= get_format_from_fourcc(header
->ddspf
.fourCC
);
229 info
->dimension
= get_dimension(header
, NULL
);
230 info
->alpha_mode
= get_alpha_mode_from_fourcc(header
->ddspf
.fourCC
);
233 /* get frame count */
234 if (info
->depth
== 1) {
235 info
->frame_count
= info
->array_size
* info
->mip_levels
;
237 info
->frame_count
= 0;
239 for (i
= 0; i
< info
->mip_levels
; i
++)
241 info
->frame_count
+= depth
;
242 if (depth
> 1) depth
/= 2;
244 info
->frame_count
*= info
->array_size
;
248 static UINT
get_bytes_per_block(DXGI_FORMAT format
)
252 case DXGI_FORMAT_BC1_UNORM
:
253 case DXGI_FORMAT_BC1_TYPELESS
:
254 case DXGI_FORMAT_BC1_UNORM_SRGB
:
256 case DXGI_FORMAT_BC2_UNORM
:
257 case DXGI_FORMAT_BC2_TYPELESS
:
258 case DXGI_FORMAT_BC2_UNORM_SRGB
:
259 case DXGI_FORMAT_BC3_UNORM
:
260 case DXGI_FORMAT_BC3_TYPELESS
:
261 case DXGI_FORMAT_BC3_UNORM_SRGB
:
264 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format
);
269 static inline DdsDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
271 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICBitmapDecoder_iface
);
274 static inline DdsDecoder
*impl_from_IWICDdsDecoder(IWICDdsDecoder
*iface
)
276 return CONTAINING_RECORD(iface
, DdsDecoder
, IWICDdsDecoder_iface
);
279 static inline DdsFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
281 return CONTAINING_RECORD(iface
, DdsFrameDecode
, IWICBitmapFrameDecode_iface
);
284 static inline DdsFrameDecode
*impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode
*iface
)
286 return CONTAINING_RECORD(iface
, DdsFrameDecode
, IWICDdsFrameDecode_iface
);
289 static HRESULT WINAPI
DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
292 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
293 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
295 if (!ppv
) return E_INVALIDARG
;
297 if (IsEqualIID(&IID_IUnknown
, iid
) ||
298 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
299 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
)) {
300 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
301 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode
, iid
)) {
302 *ppv
= &This
->IWICDdsFrameDecode_iface
;
305 return E_NOINTERFACE
;
308 IUnknown_AddRef((IUnknown
*)*ppv
);
312 static ULONG WINAPI
DdsFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
314 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
315 ULONG ref
= InterlockedIncrement(&This
->ref
);
317 TRACE("(%p) refcount=%u\n", iface
, ref
);
322 static ULONG WINAPI
DdsFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
324 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
325 ULONG ref
= InterlockedDecrement(&This
->ref
);
327 TRACE("(%p) refcount=%u\n", iface
, ref
);
330 HeapFree(GetProcessHeap(), 0, This
->data
);
331 HeapFree(GetProcessHeap(), 0, This
);
337 static HRESULT WINAPI
DdsFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
338 UINT
*puiWidth
, UINT
*puiHeight
)
340 DdsFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
342 if (!puiWidth
|| !puiHeight
) return E_INVALIDARG
;
344 *puiWidth
= This
->info
.width
;
345 *puiHeight
= This
->info
.height
;
347 TRACE("(%p) -> (%d,%d)\n", iface
, *puiWidth
, *puiHeight
);
352 static HRESULT WINAPI
DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
353 WICPixelFormatGUID
*pPixelFormat
)
355 FIXME("(%p,%p): stub.\n", iface
, pPixelFormat
);
360 static HRESULT WINAPI
DdsFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
361 double *pDpiX
, double *pDpiY
)
363 FIXME("(%p,%p,%p): stub.\n", iface
, pDpiX
, pDpiY
);
368 static HRESULT WINAPI
DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
369 IWICPalette
*pIPalette
)
371 FIXME("(%p,%p): stub.\n", iface
, pIPalette
);
376 static HRESULT WINAPI
DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
377 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
379 FIXME("(%p,%s,%u,%u,%p): stub.\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
384 static HRESULT WINAPI
DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
385 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
387 FIXME("(%p,%p): stub.\n", iface
, ppIMetadataQueryReader
);
392 static HRESULT WINAPI
DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
393 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
395 FIXME("(%p,%u,%p,%p): stub.\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
400 static HRESULT WINAPI
DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
401 IWICBitmapSource
**ppIThumbnail
)
403 FIXME("(%p,%p): stub.\n", iface
, ppIThumbnail
);
408 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl
= {
409 DdsFrameDecode_QueryInterface
,
410 DdsFrameDecode_AddRef
,
411 DdsFrameDecode_Release
,
412 DdsFrameDecode_GetSize
,
413 DdsFrameDecode_GetPixelFormat
,
414 DdsFrameDecode_GetResolution
,
415 DdsFrameDecode_CopyPalette
,
416 DdsFrameDecode_CopyPixels
,
417 DdsFrameDecode_GetMetadataQueryReader
,
418 DdsFrameDecode_GetColorContexts
,
419 DdsFrameDecode_GetThumbnail
422 static HRESULT WINAPI
DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode
*iface
,
423 REFIID iid
, void **ppv
)
425 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
426 return DdsFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
429 static ULONG WINAPI
DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode
*iface
)
431 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
432 return DdsFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
435 static ULONG WINAPI
DdsFrameDecode_Dds_Release(IWICDdsFrameDecode
*iface
)
437 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
438 return DdsFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
441 static HRESULT WINAPI
DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode
*iface
,
442 UINT
*widthInBlocks
, UINT
*heightInBlocks
)
444 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
446 if (!widthInBlocks
|| !heightInBlocks
) return E_INVALIDARG
;
448 *widthInBlocks
= This
->info
.width_in_blocks
;
449 *heightInBlocks
= This
->info
.height_in_blocks
;
451 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface
, widthInBlocks
, heightInBlocks
, *widthInBlocks
, *heightInBlocks
);
456 static HRESULT WINAPI
DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode
*iface
,
457 WICDdsFormatInfo
*formatInfo
)
459 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
461 if (!formatInfo
) return E_INVALIDARG
;
463 formatInfo
->DxgiFormat
= This
->info
.format
;
464 formatInfo
->BytesPerBlock
= This
->info
.bytes_per_block
;
465 formatInfo
->BlockWidth
= This
->info
.block_width
;
466 formatInfo
->BlockHeight
= This
->info
.block_height
;
468 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface
, formatInfo
,
469 formatInfo
->DxgiFormat
, formatInfo
->BytesPerBlock
, formatInfo
->BlockWidth
, formatInfo
->BlockHeight
);
474 static HRESULT WINAPI
DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode
*iface
,
475 const WICRect
*boundsInBlocks
, UINT stride
, UINT bufferSize
,
478 DdsFrameDecode
*This
= impl_from_IWICDdsFrameDecode(iface
);
479 int x
, y
, width
, height
;
480 UINT bytes_per_block
, frame_stride
, frame_size
, i
;
481 BYTE
*data
, *dst_buffer
;
483 TRACE("(%p,%p,%u,%u,%p)\n", iface
, boundsInBlocks
, stride
, bufferSize
, buffer
);
485 if (!buffer
) return E_INVALIDARG
;
487 bytes_per_block
= This
->info
.bytes_per_block
;
488 frame_stride
= This
->info
.width_in_blocks
* bytes_per_block
;
489 frame_size
= frame_stride
* This
->info
.height_in_blocks
;
490 if (!boundsInBlocks
) {
491 if (stride
< frame_stride
) return E_INVALIDARG
;
492 if (bufferSize
< frame_size
) return E_INVALIDARG
;
493 memcpy(buffer
, This
->data
, frame_size
);
497 x
= boundsInBlocks
->X
;
498 y
= boundsInBlocks
->Y
;
499 width
= boundsInBlocks
->Width
;
500 height
= boundsInBlocks
->Height
;
501 if (x
< 0 || y
< 0 || width
<= 0 || height
<= 0 ||
502 x
+ width
> This
->info
.width_in_blocks
||
503 y
+ height
> This
->info
.height_in_blocks
) {
506 if (stride
< width
* bytes_per_block
) return E_INVALIDARG
;
507 if (bufferSize
< stride
* height
) return E_INVALIDARG
;
509 data
= This
->data
+ (x
+ y
* This
->info
.width_in_blocks
) * bytes_per_block
;
511 for (i
= 0; i
< height
; i
++)
513 memcpy(dst_buffer
, data
, (size_t)width
* bytes_per_block
);
514 data
+= This
->info
.width_in_blocks
* bytes_per_block
;
515 dst_buffer
+= stride
;
521 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl
= {
522 DdsFrameDecode_Dds_QueryInterface
,
523 DdsFrameDecode_Dds_AddRef
,
524 DdsFrameDecode_Dds_Release
,
525 DdsFrameDecode_Dds_GetSizeInBlocks
,
526 DdsFrameDecode_Dds_GetFormatInfo
,
527 DdsFrameDecode_Dds_CopyBlocks
530 static HRESULT
DdsFrameDecode_CreateInstance(DdsFrameDecode
**frame_decode
)
532 DdsFrameDecode
*result
;
534 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
535 if (!result
) return E_OUTOFMEMORY
;
537 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &DdsFrameDecode_Vtbl
;
538 result
->IWICDdsFrameDecode_iface
.lpVtbl
= &DdsFrameDecode_Dds_Vtbl
;
541 *frame_decode
= result
;
545 static HRESULT WINAPI
DdsDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
548 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
549 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
551 if (!ppv
) return E_INVALIDARG
;
553 if (IsEqualIID(&IID_IUnknown
, iid
) ||
554 IsEqualIID(&IID_IWICBitmapDecoder
, iid
)) {
555 *ppv
= &This
->IWICBitmapDecoder_iface
;
556 } else if (IsEqualIID(&IID_IWICDdsDecoder
, iid
)) {
557 *ppv
= &This
->IWICDdsDecoder_iface
;
560 return E_NOINTERFACE
;
563 IUnknown_AddRef((IUnknown
*)*ppv
);
567 static ULONG WINAPI
DdsDecoder_AddRef(IWICBitmapDecoder
*iface
)
569 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
570 ULONG ref
= InterlockedIncrement(&This
->ref
);
572 TRACE("(%p) refcount=%u\n", iface
, ref
);
577 static ULONG WINAPI
DdsDecoder_Release(IWICBitmapDecoder
*iface
)
579 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
580 ULONG ref
= InterlockedDecrement(&This
->ref
);
582 TRACE("(%p) refcount=%u\n", iface
, ref
);
586 This
->lock
.DebugInfo
->Spare
[0] = 0;
587 DeleteCriticalSection(&This
->lock
);
588 if (This
->stream
) IStream_Release(This
->stream
);
589 HeapFree(GetProcessHeap(), 0, This
);
595 static HRESULT WINAPI
DdsDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
598 FIXME("(%p,%p,%p): stub.\n", iface
, stream
, capability
);
603 static HRESULT WINAPI
DdsDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
604 WICDecodeOptions cacheOptions
)
606 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
612 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
614 EnterCriticalSection(&This
->lock
);
616 if (This
->initialized
) {
617 hr
= WINCODEC_ERR_WRONGSTATE
;
622 hr
= IStream_Seek(pIStream
, seek
, SEEK_SET
, NULL
);
623 if (FAILED(hr
)) goto end
;
625 hr
= IStream_Read(pIStream
, &magic
, sizeof(magic
), &bytesread
);
626 if (FAILED(hr
)) goto end
;
627 if (bytesread
!= sizeof(magic
)) {
628 hr
= WINCODEC_ERR_STREAMREAD
;
631 if (magic
!= DDS_MAGIC
) {
632 hr
= WINCODEC_ERR_UNKNOWNIMAGEFORMAT
;
636 hr
= IStream_Read(pIStream
, &This
->header
, sizeof(This
->header
), &bytesread
);
637 if (FAILED(hr
)) goto end
;
638 if (bytesread
!= sizeof(This
->header
)) {
639 hr
= WINCODEC_ERR_STREAMREAD
;
642 if (This
->header
.size
!= sizeof(This
->header
)) {
643 hr
= WINCODEC_ERR_BADHEADER
;
647 if (has_extended_header(&This
->header
)) {
648 hr
= IStream_Read(pIStream
, &This
->header_dxt10
, sizeof(This
->header_dxt10
), &bytesread
);
649 if (FAILED(hr
)) goto end
;
650 if (bytesread
!= sizeof(This
->header_dxt10
)) {
651 hr
= WINCODEC_ERR_STREAMREAD
;
656 get_dds_info(&This
->info
, &This
->header
, &This
->header_dxt10
);
658 This
->initialized
= TRUE
;
659 This
->stream
= pIStream
;
660 IStream_AddRef(pIStream
);
663 LeaveCriticalSection(&This
->lock
);
668 static HRESULT WINAPI
DdsDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
669 GUID
*pguidContainerFormat
)
671 TRACE("(%p,%p)\n", iface
, pguidContainerFormat
);
673 memcpy(pguidContainerFormat
, &GUID_ContainerFormatDds
, sizeof(GUID
));
678 static HRESULT WINAPI
DdsDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
679 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
681 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
683 return get_decoder_info(&CLSID_WICDdsDecoder
, ppIDecoderInfo
);
686 static HRESULT WINAPI
DdsDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
687 IWICPalette
*pIPalette
)
689 TRACE("(%p,%p)\n", iface
, pIPalette
);
691 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
694 static HRESULT WINAPI
DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
695 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
697 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
699 FIXME("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
704 static HRESULT WINAPI
DdsDecoder_GetPreview(IWICBitmapDecoder
*iface
,
705 IWICBitmapSource
**ppIBitmapSource
)
707 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
709 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
712 static HRESULT WINAPI
DdsDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
713 UINT cCount
, IWICColorContext
**ppDdslorContexts
, UINT
*pcActualCount
)
715 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppDdslorContexts
, pcActualCount
);
717 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
720 static HRESULT WINAPI
DdsDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
721 IWICBitmapSource
**ppIThumbnail
)
723 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
725 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
728 static HRESULT WINAPI
DdsDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
731 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
733 if (!pCount
) return E_INVALIDARG
;
734 if (!This
->initialized
) return WINCODEC_ERR_WRONGSTATE
;
736 EnterCriticalSection(&This
->lock
);
738 *pCount
= This
->info
.frame_count
;
740 LeaveCriticalSection(&This
->lock
);
742 TRACE("(%p) -> %d\n", iface
, *pCount
);
747 static HRESULT WINAPI
DdsDecoder_GetFrame(IWICBitmapDecoder
*iface
,
748 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
750 DdsDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
751 UINT frame_per_texture
, array_index
, mip_level
, slice_index
, depth
;
753 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
755 if (!ppIBitmapFrame
) return E_INVALIDARG
;
757 EnterCriticalSection(&This
->lock
);
759 if (!This
->initialized
) {
760 LeaveCriticalSection(&This
->lock
);
761 return WINCODEC_ERR_WRONGSTATE
;
764 frame_per_texture
= This
->info
.frame_count
/ This
->info
.array_size
;
765 array_index
= index
/ frame_per_texture
;
766 slice_index
= index
% frame_per_texture
;
767 depth
= This
->info
.depth
;
769 while (slice_index
>= depth
)
771 slice_index
-= depth
;
773 if (depth
> 1) depth
/= 2;
776 LeaveCriticalSection(&This
->lock
);
778 return DdsDecoder_Dds_GetFrame(&This
->IWICDdsDecoder_iface
, array_index
, mip_level
, slice_index
, ppIBitmapFrame
);
781 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl
= {
782 DdsDecoder_QueryInterface
,
785 DdsDecoder_QueryCapability
,
786 DdsDecoder_Initialize
,
787 DdsDecoder_GetContainerFormat
,
788 DdsDecoder_GetDecoderInfo
,
789 DdsDecoder_CopyPalette
,
790 DdsDecoder_GetMetadataQueryReader
,
791 DdsDecoder_GetPreview
,
792 DdsDecoder_GetColorContexts
,
793 DdsDecoder_GetThumbnail
,
794 DdsDecoder_GetFrameCount
,
798 static HRESULT WINAPI
DdsDecoder_Dds_QueryInterface(IWICDdsDecoder
*iface
,
799 REFIID iid
, void **ppv
)
801 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
802 return DdsDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
805 static ULONG WINAPI
DdsDecoder_Dds_AddRef(IWICDdsDecoder
*iface
)
807 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
808 return DdsDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
811 static ULONG WINAPI
DdsDecoder_Dds_Release(IWICDdsDecoder
*iface
)
813 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
814 return DdsDecoder_Release(&This
->IWICBitmapDecoder_iface
);
817 static HRESULT WINAPI
DdsDecoder_Dds_GetParameters(IWICDdsDecoder
*iface
,
818 WICDdsParameters
*parameters
)
820 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
823 if (!parameters
) return E_INVALIDARG
;
825 EnterCriticalSection(&This
->lock
);
827 if (!This
->initialized
) {
828 hr
= WINCODEC_ERR_WRONGSTATE
;
832 parameters
->Width
= This
->info
.width
;
833 parameters
->Height
= This
->info
.height
;
834 parameters
->Depth
= This
->info
.depth
;
835 parameters
->MipLevels
= This
->info
.mip_levels
;
836 parameters
->ArraySize
= This
->info
.array_size
;
837 parameters
->DxgiFormat
= This
->info
.format
;
838 parameters
->Dimension
= This
->info
.dimension
;
839 parameters
->AlphaMode
= This
->info
.alpha_mode
;
841 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
842 iface
, parameters
->Width
, parameters
->Height
, parameters
->Depth
, parameters
->MipLevels
,
843 parameters
->ArraySize
, parameters
->DxgiFormat
, parameters
->Dimension
, parameters
->AlphaMode
);
848 LeaveCriticalSection(&This
->lock
);
853 static HRESULT WINAPI
DdsDecoder_Dds_GetFrame(IWICDdsDecoder
*iface
,
854 UINT arrayIndex
, UINT mipLevel
, UINT sliceIndex
,
855 IWICBitmapFrameDecode
**bitmapFrame
)
857 DdsDecoder
*This
= impl_from_IWICDdsDecoder(iface
);
860 UINT width
, height
, depth
, width_in_blocks
, height_in_blocks
, size
;
861 UINT frame_width
= 0, frame_height
= 0, frame_width_in_blocks
= 0, frame_height_in_blocks
= 0, frame_size
= 0;
862 UINT bytes_per_block
, bytesread
, i
;
863 DdsFrameDecode
*frame_decode
= NULL
;
865 TRACE("(%p,%u,%u,%u,%p)\n", iface
, arrayIndex
, mipLevel
, sliceIndex
, bitmapFrame
);
867 if (!bitmapFrame
) return E_INVALIDARG
;
869 EnterCriticalSection(&This
->lock
);
871 if (!This
->initialized
) {
872 hr
= WINCODEC_ERR_WRONGSTATE
;
875 if (arrayIndex
>= This
->info
.array_size
|| mipLevel
>= This
->info
.mip_levels
|| sliceIndex
>= This
->info
.depth
) {
880 bytes_per_block
= get_bytes_per_block(This
->info
.format
);
881 seek
.QuadPart
= sizeof(DWORD
) + sizeof(DDS_HEADER
);
882 if (has_extended_header(&This
->header
)) seek
.QuadPart
+= sizeof(DDS_HEADER_DXT10
);
884 width
= This
->info
.width
;
885 height
= This
->info
.height
;
886 depth
= This
->info
.depth
;
887 for (i
= 0; i
< This
->info
.mip_levels
; i
++)
889 width_in_blocks
= (width
+ DDS_BLOCK_WIDTH
- 1) / DDS_BLOCK_WIDTH
;
890 height_in_blocks
= (height
+ DDS_BLOCK_HEIGHT
- 1) / DDS_BLOCK_HEIGHT
;
891 size
= width_in_blocks
* height_in_blocks
* bytes_per_block
;
894 seek
.QuadPart
+= size
* depth
;
895 } else if (i
== mipLevel
){
896 seek
.QuadPart
+= size
* sliceIndex
;
898 frame_height
= height
;
899 frame_width_in_blocks
= width_in_blocks
;
900 frame_height_in_blocks
= height_in_blocks
;
901 frame_size
= frame_width_in_blocks
* frame_height_in_blocks
* bytes_per_block
;
902 if (arrayIndex
== 0) break;
904 seek
.QuadPart
+= arrayIndex
* size
* depth
;
906 if (width
> 1) width
/= 2;
907 if (height
> 1) height
/= 2;
908 if (depth
> 1) depth
/= 2;
911 hr
= DdsFrameDecode_CreateInstance(&frame_decode
);
912 if (hr
!= S_OK
) goto end
;
913 frame_decode
->info
.width
= frame_width
;
914 frame_decode
->info
.height
= frame_height
;
915 frame_decode
->info
.format
= This
->info
.format
;
916 frame_decode
->info
.bytes_per_block
= bytes_per_block
;
917 frame_decode
->info
.block_width
= DDS_BLOCK_WIDTH
;
918 frame_decode
->info
.block_height
= DDS_BLOCK_HEIGHT
;
919 frame_decode
->info
.width_in_blocks
= frame_width_in_blocks
;
920 frame_decode
->info
.height_in_blocks
= frame_height_in_blocks
;
921 frame_decode
->data
= HeapAlloc(GetProcessHeap(), 0, frame_size
);
922 hr
= IStream_Seek(This
->stream
, seek
, SEEK_SET
, NULL
);
923 if (hr
!= S_OK
) goto end
;
924 hr
= IStream_Read(This
->stream
, frame_decode
->data
, frame_size
, &bytesread
);
925 if (hr
!= S_OK
|| bytesread
!= frame_size
) {
926 hr
= WINCODEC_ERR_STREAMREAD
;
929 *bitmapFrame
= &frame_decode
->IWICBitmapFrameDecode_iface
;
934 LeaveCriticalSection(&This
->lock
);
936 if (hr
!= S_OK
&& frame_decode
) DdsFrameDecode_Release(&frame_decode
->IWICBitmapFrameDecode_iface
);
941 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl
= {
942 DdsDecoder_Dds_QueryInterface
,
943 DdsDecoder_Dds_AddRef
,
944 DdsDecoder_Dds_Release
,
945 DdsDecoder_Dds_GetParameters
,
946 DdsDecoder_Dds_GetFrame
949 HRESULT
DdsDecoder_CreateInstance(REFIID iid
, void** ppv
)
954 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
958 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder
));
959 if (!This
) return E_OUTOFMEMORY
;
961 This
->IWICBitmapDecoder_iface
.lpVtbl
= &DdsDecoder_Vtbl
;
962 This
->IWICDdsDecoder_iface
.lpVtbl
= &DdsDecoder_Dds_Vtbl
;
964 This
->initialized
= FALSE
;
966 InitializeCriticalSection(&This
->lock
);
967 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": DdsDecoder.lock");
969 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
970 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);