libport: Remove support for PPC32.
[wine.git] / dlls / windowscodecs / ddsformat.c
blob7a27c48dee0244b4a685e02e35995e637a8fec64
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 #include "config.h"
20 #include "wine/port.h"
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 #define DDS_MAGIC 0x20534444
37 #ifndef MAKEFOURCC
38 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
39 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
40 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
41 #endif
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
63 typedef struct {
64 DWORD size;
65 DWORD flags;
66 DWORD fourCC;
67 DWORD rgbBitCount;
68 DWORD rBitMask;
69 DWORD gBitMask;
70 DWORD bBitMask;
71 DWORD aBitMask;
72 } DDS_PIXELFORMAT;
74 typedef struct {
75 DWORD size;
76 DWORD flags;
77 DWORD height;
78 DWORD width;
79 DWORD pitchOrLinearSize;
80 DWORD depth;
81 DWORD mipMapCount;
82 DWORD reserved1[11];
83 DDS_PIXELFORMAT ddspf;
84 DWORD caps;
85 DWORD caps2;
86 DWORD caps3;
87 DWORD caps4;
88 DWORD reserved2;
89 } DDS_HEADER;
91 typedef struct {
92 DWORD dxgiFormat;
93 DWORD resourceDimension;
94 DWORD miscFlag;
95 DWORD arraySize;
96 DWORD miscFlags2;
97 } DDS_HEADER_DXT10;
99 typedef struct dds_info {
100 UINT width;
101 UINT height;
102 UINT depth;
103 UINT mip_levels;
104 UINT array_size;
105 UINT frame_count;
106 DXGI_FORMAT format;
107 WICDdsDimension dimension;
108 WICDdsAlphaMode alpha_mode;
109 } dds_info;
111 typedef struct dds_frame_info {
112 UINT width;
113 UINT height;
114 DXGI_FORMAT format;
115 UINT bytes_per_block;
116 UINT block_width;
117 UINT block_height;
118 UINT width_in_blocks;
119 UINT height_in_blocks;
120 } dds_frame_info;
122 typedef struct DdsDecoder {
123 IWICBitmapDecoder IWICBitmapDecoder_iface;
124 IWICDdsDecoder IWICDdsDecoder_iface;
125 LONG ref;
126 BOOL initialized;
127 IStream *stream;
128 CRITICAL_SECTION lock;
129 DDS_HEADER header;
130 DDS_HEADER_DXT10 header_dxt10;
131 dds_info info;
132 } DdsDecoder;
134 typedef struct DdsFrameDecode {
135 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
136 IWICDdsFrameDecode IWICDdsFrameDecode_iface;
137 LONG ref;
138 BYTE *data;
139 dds_frame_info info;
140 } DdsFrameDecode;
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)
152 if (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;
161 } else {
162 if (header->caps2 & DDSCAPS2_CUBEMAP) {
163 return WICDdsTextureCube;
164 } else if (header->caps2 & DDSCAPS2_VOLUME) {
165 return WICDdsTexture3D;
166 } else {
167 return WICDdsTexture2D;
172 static DXGI_FORMAT get_format_from_fourcc(DWORD fourcc)
174 switch (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;
187 default:
188 /* there are DDS files where fourCC is set directly to DXGI_FORMAT enumeration value */
189 return fourcc;
193 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
195 switch (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;
204 default:
205 return WICDdsAlphaModeUnknown;
209 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
211 int i;
212 UINT depth;
214 info->width = header->width;
215 info->height = header->height;
216 info->depth = 1;
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;
227 } else {
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;
236 } else {
237 info->frame_count = 0;
238 depth = info->depth;
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)
250 switch(format)
252 case DXGI_FORMAT_BC1_UNORM:
253 case DXGI_FORMAT_BC1_TYPELESS:
254 case DXGI_FORMAT_BC1_UNORM_SRGB:
255 return 8;
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:
262 return 16;
263 default:
264 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
265 return 0;
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,
290 void **ppv)
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;
303 } else {
304 *ppv = NULL;
305 return E_NOINTERFACE;
308 IUnknown_AddRef((IUnknown*)*ppv);
309 return S_OK;
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);
319 return 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);
329 if (ref == 0) {
330 HeapFree(GetProcessHeap(), 0, This->data);
331 HeapFree(GetProcessHeap(), 0, This);
334 return ref;
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);
349 return S_OK;
352 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
353 WICPixelFormatGUID *pPixelFormat)
355 FIXME("(%p,%p): stub.\n", iface, pPixelFormat);
357 return E_NOTIMPL;
360 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
361 double *pDpiX, double *pDpiY)
363 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
365 return E_NOTIMPL;
368 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
369 IWICPalette *pIPalette)
371 FIXME("(%p,%p): stub.\n", iface, pIPalette);
373 return E_NOTIMPL;
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);
381 return E_NOTIMPL;
384 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
385 IWICMetadataQueryReader **ppIMetadataQueryReader)
387 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
389 return E_NOTIMPL;
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);
397 return E_NOTIMPL;
400 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
401 IWICBitmapSource **ppIThumbnail)
403 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
405 return E_NOTIMPL;
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);
453 return S_OK;
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);
471 return S_OK;
474 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
475 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
476 BYTE *buffer)
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);
494 return S_OK;
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) {
504 return E_INVALIDARG;
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;
510 dst_buffer = buffer;
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;
518 return S_OK;
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;
539 result->ref = 1;
541 *frame_decode = result;
542 return S_OK;
545 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
546 void **ppv)
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;
558 } else {
559 *ppv = NULL;
560 return E_NOINTERFACE;
563 IUnknown_AddRef((IUnknown*)*ppv);
564 return S_OK;
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);
574 return 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);
584 if (ref == 0)
586 This->lock.DebugInfo->Spare[0] = 0;
587 DeleteCriticalSection(&This->lock);
588 if (This->stream) IStream_Release(This->stream);
589 HeapFree(GetProcessHeap(), 0, This);
592 return ref;
595 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
596 DWORD *capability)
598 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
600 return E_NOTIMPL;
603 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
604 WICDecodeOptions cacheOptions)
606 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
607 HRESULT hr;
608 LARGE_INTEGER seek;
609 DWORD magic;
610 ULONG bytesread;
612 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
614 EnterCriticalSection(&This->lock);
616 if (This->initialized) {
617 hr = WINCODEC_ERR_WRONGSTATE;
618 goto end;
621 seek.QuadPart = 0;
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;
629 goto end;
631 if (magic != DDS_MAGIC) {
632 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
633 goto end;
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;
640 goto end;
642 if (This->header.size != sizeof(This->header)) {
643 hr = WINCODEC_ERR_BADHEADER;
644 goto end;
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;
652 goto end;
656 get_dds_info(&This->info, &This->header, &This->header_dxt10);
658 This->initialized = TRUE;
659 This->stream = pIStream;
660 IStream_AddRef(pIStream);
662 end:
663 LeaveCriticalSection(&This->lock);
665 return hr;
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));
675 return S_OK;
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);
701 return E_NOTIMPL;
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,
729 UINT *pCount)
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);
744 return S_OK;
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;
768 mip_level = 0;
769 while (slice_index >= depth)
771 slice_index -= depth;
772 mip_level++;
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,
783 DdsDecoder_AddRef,
784 DdsDecoder_Release,
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,
795 DdsDecoder_GetFrame
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);
821 HRESULT hr;
823 if (!parameters) return E_INVALIDARG;
825 EnterCriticalSection(&This->lock);
827 if (!This->initialized) {
828 hr = WINCODEC_ERR_WRONGSTATE;
829 goto end;
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);
845 hr = S_OK;
847 end:
848 LeaveCriticalSection(&This->lock);
850 return hr;
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);
858 HRESULT hr;
859 LARGE_INTEGER seek;
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;
873 goto end;
875 if (arrayIndex >= This->info.array_size || mipLevel >= This->info.mip_levels || sliceIndex >= This->info.depth) {
876 hr = E_INVALIDARG;
877 goto end;
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;
893 if (i < mipLevel) {
894 seek.QuadPart += size * depth;
895 } else if (i == mipLevel){
896 seek.QuadPart += size * sliceIndex;
897 frame_width = width;
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;
927 goto end;
929 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
931 hr = S_OK;
933 end:
934 LeaveCriticalSection(&This->lock);
936 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
938 return hr;
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)
951 DdsDecoder *This;
952 HRESULT ret;
954 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
956 *ppv = NULL;
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;
963 This->ref = 1;
964 This->initialized = FALSE;
965 This->stream = NULL;
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);
972 return ret;