widl: Always check the runtimeclass interfaces presence.
[wine/zf.git] / dlls / windowscodecs / ddsformat.c
blob873d4f1bb1f4b740f8c03d12d7569c5928020be9
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 <stdarg.h>
31 #define COBJMACROS
33 #include "windef.h"
34 #include "winbase.h"
35 #include "objbase.h"
37 #include "wincodecs_private.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
43 #define DDS_MAGIC 0x20534444
44 #ifndef MAKEFOURCC
45 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
46 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
47 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
48 #endif
50 #define GET_RGB565_R(color) ((BYTE)(((color) >> 11) & 0x1F))
51 #define GET_RGB565_G(color) ((BYTE)(((color) >> 5) & 0x3F))
52 #define GET_RGB565_B(color) ((BYTE)(((color) >> 0) & 0x1F))
53 #define MAKE_RGB565(r, g, b) ((WORD)(((BYTE)(r) << 11) | ((BYTE)(g) << 5) | (BYTE)(b)))
54 #define MAKE_ARGB(a, r, g, b) (((DWORD)(a) << 24) | ((DWORD)(r) << 16) | ((DWORD)(g) << 8) | (DWORD)(b))
56 #define DDPF_ALPHAPIXELS 0x00000001
57 #define DDPF_ALPHA 0x00000002
58 #define DDPF_FOURCC 0x00000004
59 #define DDPF_PALETTEINDEXED8 0x00000020
60 #define DDPF_RGB 0x00000040
61 #define DDPF_LUMINANCE 0x00020000
62 #define DDPF_BUMPDUDV 0x00080000
64 #define DDSCAPS2_CUBEMAP 0x00000200
65 #define DDSCAPS2_VOLUME 0x00200000
67 #define DDS_DIMENSION_TEXTURE1D 2
68 #define DDS_DIMENSION_TEXTURE2D 3
69 #define DDS_DIMENSION_TEXTURE3D 4
71 #define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004
73 #define DDS_BLOCK_WIDTH 4
74 #define DDS_BLOCK_HEIGHT 4
76 typedef struct {
77 DWORD size;
78 DWORD flags;
79 DWORD fourCC;
80 DWORD rgbBitCount;
81 DWORD rBitMask;
82 DWORD gBitMask;
83 DWORD bBitMask;
84 DWORD aBitMask;
85 } DDS_PIXELFORMAT;
87 typedef struct {
88 DWORD size;
89 DWORD flags;
90 DWORD height;
91 DWORD width;
92 DWORD pitchOrLinearSize;
93 DWORD depth;
94 DWORD mipMapCount;
95 DWORD reserved1[11];
96 DDS_PIXELFORMAT ddspf;
97 DWORD caps;
98 DWORD caps2;
99 DWORD caps3;
100 DWORD caps4;
101 DWORD reserved2;
102 } DDS_HEADER;
104 typedef struct {
105 DWORD dxgiFormat;
106 DWORD resourceDimension;
107 DWORD miscFlag;
108 DWORD arraySize;
109 DWORD miscFlags2;
110 } DDS_HEADER_DXT10;
112 typedef struct dds_info {
113 UINT width;
114 UINT height;
115 UINT depth;
116 UINT mip_levels;
117 UINT array_size;
118 UINT frame_count;
119 UINT data_offset;
120 UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/
121 DXGI_FORMAT format;
122 WICDdsDimension dimension;
123 WICDdsAlphaMode alpha_mode;
124 const GUID *pixel_format;
125 UINT pixel_format_bpp;
126 } dds_info;
128 typedef struct dds_frame_info {
129 UINT width;
130 UINT height;
131 DXGI_FORMAT format;
132 UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/
133 UINT block_width;
134 UINT block_height;
135 UINT width_in_blocks;
136 UINT height_in_blocks;
137 const GUID *pixel_format;
138 UINT pixel_format_bpp;
139 } dds_frame_info;
141 typedef struct DdsDecoder {
142 IWICBitmapDecoder IWICBitmapDecoder_iface;
143 IWICDdsDecoder IWICDdsDecoder_iface;
144 IWICWineDecoder IWICWineDecoder_iface;
145 LONG ref;
146 BOOL initialized;
147 IStream *stream;
148 CRITICAL_SECTION lock;
149 dds_info info;
150 } DdsDecoder;
152 typedef struct DdsFrameDecode {
153 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
154 IWICDdsFrameDecode IWICDdsFrameDecode_iface;
155 LONG ref;
156 BYTE *block_data;
157 BYTE *pixel_data;
158 CRITICAL_SECTION lock;
159 dds_frame_info info;
160 } DdsFrameDecode;
162 typedef struct DdsEncoder {
163 IWICBitmapEncoder IWICBitmapEncoder_iface;
164 LONG ref;
165 CRITICAL_SECTION lock;
166 IStream *stream;
167 UINT frame_count;
168 BOOL uncommitted_frame;
169 BOOL committed;
170 } DdsEncoder;
172 static struct dds_format {
173 DDS_PIXELFORMAT pixel_format;
174 const GUID *wic_format;
175 UINT wic_format_bpp;
176 DXGI_FORMAT dxgi_format;
177 } dds_format_table[] = {
178 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 },
179 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC1_UNORM },
180 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 },
181 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC2_UNORM },
182 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 },
183 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC2_UNORM },
184 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 },
185 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC3_UNORM },
186 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 },
187 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC3_UNORM },
188 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 },
189 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
190 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 },
191 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_SNORM },
192 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 },
193 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
194 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 },
195 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_SNORM },
196 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 },
197 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
198 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 },
199 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
200 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 },
201 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_R8G8_B8G8_UNORM },
202 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 },
203 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_G8R8_G8B8_UNORM },
204 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 },
205 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN },
206 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 },
207 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
208 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 },
209 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_SNORM },
210 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 },
211 &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
212 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 },
213 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_FLOAT },
214 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 },
215 &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
216 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 },
217 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
218 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 },
219 &GUID_WICPixelFormatUndefined, 32, DXGI_FORMAT_R32G32_FLOAT },
220 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 },
221 &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
222 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 },
223 &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
224 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0 },
225 &GUID_WICPixelFormat32bppRGB, 32, DXGI_FORMAT_UNKNOWN },
226 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 },
227 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
228 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 },
229 &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
230 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
231 * For "correct" one, the RGB masks should be 0x3FF,0xFFC00,0x3FF00000.
232 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
233 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF00000,0xFFC00,0x3FF,0xC0000000 },
234 &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
235 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 },
236 &GUID_WICPixelFormat32bppRGBA1010102, 32, DXGI_FORMAT_UNKNOWN },
237 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 },
238 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_UNORM },
239 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 },
240 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
241 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0xFF0000,0x00FF00,0x0000FF,0 },
242 &GUID_WICPixelFormat24bppBGR, 24, DXGI_FORMAT_UNKNOWN },
243 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0x0000FF,0x00FF00,0xFF0000,0 },
244 &GUID_WICPixelFormat24bppRGB, 24, DXGI_FORMAT_UNKNOWN },
245 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 },
246 &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
247 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0 },
248 &GUID_WICPixelFormat16bppBGR555, 16, DXGI_FORMAT_UNKNOWN },
249 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 },
250 &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
251 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 },
252 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_B4G4R4A4_UNORM },
253 { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF },
254 &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
255 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 },
256 &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
257 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 },
258 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R8G8_UNORM },
259 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 },
260 &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
261 { { 0 }, &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
262 { { 0 }, &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
263 { { 0 }, &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
264 { { 0 }, &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
265 { { 0 }, &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
266 { { 0 }, &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
267 { { 0 }, &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
268 { { 0 }, &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
269 { { 0 }, &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
270 { { 0 }, &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
271 { { 0 }, &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
272 { { 0 }, &GUID_WICPixelFormat32bppRGBE, 32, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
273 { { 0 }, &GUID_WICPixelFormat32bppRGBA1010102XR, 32, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },
274 { { 0 }, &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
275 { { 0 }, &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
276 { { 0 }, &GUID_WICPixelFormat96bppRGBFloat, 96, DXGI_FORMAT_R32G32B32_FLOAT },
277 { { 0 }, &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
278 { { 0 }, &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN }
281 static DXGI_FORMAT compressed_formats[] = {
282 DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB,
283 DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB,
284 DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB,
285 DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM,
286 DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM,
287 DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16,
288 DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB
291 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **);
293 static DWORD rgb565_to_argb(WORD color, BYTE alpha)
295 return MAKE_ARGB(alpha, (GET_RGB565_R(color) * 0xFF + 0x0F) / 0x1F,
296 (GET_RGB565_G(color) * 0xFF + 0x1F) / 0x3F,
297 (GET_RGB565_B(color) * 0xFF + 0x0F) / 0x1F);
300 static inline BOOL has_extended_header(DDS_HEADER *header)
302 return (header->ddspf.flags & DDPF_FOURCC) &&
303 (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'));
306 static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
308 if (header_dxt10) {
309 if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube;
310 switch (header_dxt10->resourceDimension)
312 case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D;
313 case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D;
314 case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D;
315 default: return WICDdsTexture2D;
317 } else {
318 if (header->caps2 & DDSCAPS2_CUBEMAP) {
319 return WICDdsTextureCube;
320 } else if (header->caps2 & DDSCAPS2_VOLUME) {
321 return WICDdsTexture3D;
322 } else {
323 return WICDdsTexture2D;
328 static struct dds_format *get_dds_format(DDS_PIXELFORMAT *pixel_format)
330 UINT i;
332 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
334 if ((pixel_format->flags & dds_format_table[i].pixel_format.flags) &&
335 (pixel_format->fourCC == dds_format_table[i].pixel_format.fourCC) &&
336 (pixel_format->rgbBitCount == dds_format_table[i].pixel_format.rgbBitCount) &&
337 (pixel_format->rBitMask == dds_format_table[i].pixel_format.rBitMask) &&
338 (pixel_format->gBitMask == dds_format_table[i].pixel_format.gBitMask) &&
339 (pixel_format->bBitMask == dds_format_table[i].pixel_format.bBitMask) &&
340 (pixel_format->aBitMask == dds_format_table[i].pixel_format.aBitMask))
341 return dds_format_table + i;
344 return dds_format_table + ARRAY_SIZE(dds_format_table) - 1;
347 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
349 switch (fourcc)
351 case MAKEFOURCC('D', 'X', 'T', '1'):
352 case MAKEFOURCC('D', 'X', 'T', '2'):
353 case MAKEFOURCC('D', 'X', 'T', '4'):
354 return WICDdsAlphaModePremultiplied;
355 default:
356 return WICDdsAlphaModeUnknown;
360 static UINT get_bytes_per_block_from_format(DXGI_FORMAT format)
362 /* for uncompressed format, return bytes per pixel*/
363 switch (format)
365 case DXGI_FORMAT_R8_TYPELESS:
366 case DXGI_FORMAT_R8_UNORM:
367 case DXGI_FORMAT_R8_UINT:
368 case DXGI_FORMAT_R8_SNORM:
369 case DXGI_FORMAT_R8_SINT:
370 case DXGI_FORMAT_A8_UNORM:
371 return 1;
372 case DXGI_FORMAT_R8G8_TYPELESS:
373 case DXGI_FORMAT_R8G8_UNORM:
374 case DXGI_FORMAT_R8G8_UINT:
375 case DXGI_FORMAT_R8G8_SNORM:
376 case DXGI_FORMAT_R8G8_SINT:
377 case DXGI_FORMAT_R16_TYPELESS:
378 case DXGI_FORMAT_R16_FLOAT:
379 case DXGI_FORMAT_D16_UNORM:
380 case DXGI_FORMAT_R16_UNORM:
381 case DXGI_FORMAT_R16_UINT:
382 case DXGI_FORMAT_R16_SNORM:
383 case DXGI_FORMAT_R16_SINT:
384 case DXGI_FORMAT_B5G6R5_UNORM:
385 case DXGI_FORMAT_B5G5R5A1_UNORM:
386 case DXGI_FORMAT_B4G4R4A4_UNORM:
387 return 2;
388 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
389 case DXGI_FORMAT_R10G10B10A2_UNORM:
390 case DXGI_FORMAT_R10G10B10A2_UINT:
391 case DXGI_FORMAT_R11G11B10_FLOAT:
392 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
393 case DXGI_FORMAT_R8G8B8A8_UNORM:
394 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
395 case DXGI_FORMAT_R8G8B8A8_UINT:
396 case DXGI_FORMAT_R8G8B8A8_SNORM:
397 case DXGI_FORMAT_R8G8B8A8_SINT:
398 case DXGI_FORMAT_R16G16_TYPELESS:
399 case DXGI_FORMAT_R16G16_FLOAT:
400 case DXGI_FORMAT_R16G16_UNORM:
401 case DXGI_FORMAT_R16G16_UINT:
402 case DXGI_FORMAT_R16G16_SNORM:
403 case DXGI_FORMAT_R16G16_SINT:
404 case DXGI_FORMAT_R32_TYPELESS:
405 case DXGI_FORMAT_D32_FLOAT:
406 case DXGI_FORMAT_R32_FLOAT:
407 case DXGI_FORMAT_R32_UINT:
408 case DXGI_FORMAT_R32_SINT:
409 case DXGI_FORMAT_R24G8_TYPELESS:
410 case DXGI_FORMAT_D24_UNORM_S8_UINT:
411 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
412 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
413 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
414 case DXGI_FORMAT_R8G8_B8G8_UNORM:
415 case DXGI_FORMAT_G8R8_G8B8_UNORM:
416 case DXGI_FORMAT_B8G8R8A8_UNORM:
417 case DXGI_FORMAT_B8G8R8X8_UNORM:
418 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
419 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
420 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
421 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
422 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
423 return 4;
424 case DXGI_FORMAT_BC1_UNORM:
425 case DXGI_FORMAT_BC1_TYPELESS:
426 case DXGI_FORMAT_BC1_UNORM_SRGB:
427 case DXGI_FORMAT_BC4_TYPELESS:
428 case DXGI_FORMAT_BC4_UNORM:
429 case DXGI_FORMAT_BC4_SNORM:
430 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
431 case DXGI_FORMAT_R16G16B16A16_FLOAT:
432 case DXGI_FORMAT_R16G16B16A16_UNORM:
433 case DXGI_FORMAT_R16G16B16A16_UINT:
434 case DXGI_FORMAT_R16G16B16A16_SNORM:
435 case DXGI_FORMAT_R16G16B16A16_SINT:
436 case DXGI_FORMAT_R32G32_TYPELESS:
437 case DXGI_FORMAT_R32G32_FLOAT:
438 case DXGI_FORMAT_R32G32_UINT:
439 case DXGI_FORMAT_R32G32_SINT:
440 case DXGI_FORMAT_R32G8X24_TYPELESS:
441 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
442 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
443 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
444 return 8;
445 case DXGI_FORMAT_R32G32B32_TYPELESS:
446 case DXGI_FORMAT_R32G32B32_FLOAT:
447 case DXGI_FORMAT_R32G32B32_UINT:
448 case DXGI_FORMAT_R32G32B32_SINT:
449 return 12;
450 case DXGI_FORMAT_BC2_UNORM:
451 case DXGI_FORMAT_BC2_TYPELESS:
452 case DXGI_FORMAT_BC2_UNORM_SRGB:
453 case DXGI_FORMAT_BC3_UNORM:
454 case DXGI_FORMAT_BC3_TYPELESS:
455 case DXGI_FORMAT_BC3_UNORM_SRGB:
456 case DXGI_FORMAT_BC5_TYPELESS:
457 case DXGI_FORMAT_BC5_UNORM:
458 case DXGI_FORMAT_BC5_SNORM:
459 case DXGI_FORMAT_BC6H_TYPELESS:
460 case DXGI_FORMAT_BC6H_UF16:
461 case DXGI_FORMAT_BC6H_SF16:
462 case DXGI_FORMAT_BC7_TYPELESS:
463 case DXGI_FORMAT_BC7_UNORM:
464 case DXGI_FORMAT_BC7_UNORM_SRGB:
465 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
466 case DXGI_FORMAT_R32G32B32A32_FLOAT:
467 case DXGI_FORMAT_R32G32B32A32_UINT:
468 case DXGI_FORMAT_R32G32B32A32_SINT:
469 return 16;
470 default:
471 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
472 return 0;
476 static const GUID *dxgi_format_to_wic_format(DXGI_FORMAT dxgi_format)
478 UINT i;
479 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
481 if (dds_format_table[i].pixel_format.size == 0 &&
482 dds_format_table[i].dxgi_format == dxgi_format)
483 return dds_format_table[i].wic_format;
485 return &GUID_WICPixelFormatUndefined;
488 static BOOL is_compressed(DXGI_FORMAT format)
490 UINT i;
492 for (i = 0; i < ARRAY_SIZE(compressed_formats); i++)
494 if (format == compressed_formats[i]) return TRUE;
496 return FALSE;
499 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
501 int i;
502 UINT depth;
503 struct dds_format *format_info;
505 info->width = header->width;
506 info->height = header->height;
507 info->depth = 1;
508 info->mip_levels = 1;
509 info->array_size = 1;
510 if (header->depth) info->depth = header->depth;
511 if (header->mipMapCount) info->mip_levels = header->mipMapCount;
513 if (has_extended_header(header)) {
514 if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize;
515 info->format = header_dxt10->dxgiFormat;
516 info->dimension = get_dimension(NULL, header_dxt10);
517 info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008;
518 info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10);
519 if (is_compressed(info->format)) {
520 info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ?
521 &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA;
522 info->pixel_format_bpp = 32;
523 } else {
524 info->pixel_format = dxgi_format_to_wic_format(info->format);
525 info->pixel_format_bpp = get_bytes_per_block_from_format(info->format) * 8;
527 } else {
528 format_info = get_dds_format(&header->ddspf);
529 info->format = format_info->dxgi_format;
530 info->dimension = get_dimension(header, NULL);
531 info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC);
532 info->data_offset = sizeof(DWORD) + sizeof(*header);
533 info->pixel_format = format_info->wic_format;
534 info->pixel_format_bpp = format_info->wic_format_bpp;
537 if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) {
538 info->bytes_per_block = header->ddspf.rgbBitCount / 8;
539 } else {
540 info->bytes_per_block = get_bytes_per_block_from_format(info->format);
543 /* get frame count */
545 if (info->depth == 1) {
546 info->frame_count = info->array_size * info->mip_levels;
547 } else {
548 info->frame_count = 0;
549 depth = info->depth;
550 for (i = 0; i < info->mip_levels; i++)
552 info->frame_count += depth;
553 if (depth > 1) depth /= 2;
555 info->frame_count *= info->array_size;
557 if (info->dimension == WICDdsTextureCube) info->frame_count *= 6;
560 static void decode_block(const BYTE *block_data, UINT block_count, DXGI_FORMAT format,
561 UINT width, UINT height, DWORD *buffer)
563 const BYTE *block, *color_indices, *alpha_indices, *alpha_table;
564 int i, j, x, y, block_x, block_y, color_index, alpha_index;
565 int block_size, color_offset, color_indices_offset;
566 WORD color[4], color_value = 0;
567 BYTE alpha[8], alpha_value = 0;
569 if (format == DXGI_FORMAT_BC1_UNORM) {
570 block_size = 8;
571 color_offset = 0;
572 color_indices_offset = 4;
573 } else {
574 block_size = 16;
575 color_offset = 8;
576 color_indices_offset = 12;
578 block_x = 0;
579 block_y = 0;
581 for (i = 0; i < block_count; i++)
583 block = block_data + i * block_size;
585 color[0] = *((WORD *)(block + color_offset));
586 color[1] = *((WORD *)(block + color_offset + 2));
587 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) * 2 + GET_RGB565_R(color[1]) + 1) / 3),
588 ((GET_RGB565_G(color[0]) * 2 + GET_RGB565_G(color[1]) + 1) / 3),
589 ((GET_RGB565_B(color[0]) * 2 + GET_RGB565_B(color[1]) + 1) / 3));
590 color[3] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) * 2 + 1) / 3),
591 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) * 2 + 1) / 3),
592 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) * 2 + 1) / 3));
594 switch (format)
596 case DXGI_FORMAT_BC1_UNORM:
597 if (color[0] <= color[1]) {
598 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) + 1) / 2),
599 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) + 1) / 2),
600 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) + 1) / 2));
601 color[3] = 0;
603 break;
604 case DXGI_FORMAT_BC2_UNORM:
605 alpha_table = block;
606 break;
607 case DXGI_FORMAT_BC3_UNORM:
608 alpha[0] = *block;
609 alpha[1] = *(block + 1);
610 if (alpha[0] > alpha[1]) {
611 for (j = 2; j < 8; j++)
613 alpha[j] = (BYTE)((alpha[0] * (8 - j) + alpha[1] * (j - 1) + 3) / 7);
615 } else {
616 for (j = 2; j < 6; j++)
618 alpha[j] = (BYTE)((alpha[0] * (6 - j) + alpha[1] * (j - 1) + 2) / 5);
620 alpha[6] = 0;
621 alpha[7] = 0xFF;
623 alpha_indices = block + 2;
624 break;
625 default:
626 break;
629 color_indices = block + color_indices_offset;
630 for (j = 0; j < 16; j++)
632 x = block_x + j % 4;
633 y = block_y + j / 4;
634 if (x >= width || y >= height) continue;
636 color_index = (color_indices[j / 4] >> ((j % 4) * 2)) & 0x3;
637 color_value = color[color_index];
639 switch (format)
641 case DXGI_FORMAT_BC1_UNORM:
642 if ((color[0] <= color[1]) && !color_value) {
643 color_value = 0;
644 alpha_value = 0;
645 } else {
646 alpha_value = 0xFF;
648 break;
649 case DXGI_FORMAT_BC2_UNORM:
650 alpha_value = (alpha_table[j / 2] >> (j % 2) * 4) & 0xF;
651 alpha_value = (BYTE)((alpha_value * 0xFF + 0x7)/ 0xF);
652 break;
653 case DXGI_FORMAT_BC3_UNORM:
654 alpha_index = (*((DWORD *)(alpha_indices + (j / 8) * 3)) >> ((j % 8) * 3)) & 0x7;
655 alpha_value = alpha[alpha_index];
656 break;
657 default:
658 break;
660 buffer[x + y * width] = rgb565_to_argb(color_value, alpha_value);
663 block_x += DDS_BLOCK_WIDTH;
664 if (block_x >= width) {
665 block_x = 0;
666 block_y += DDS_BLOCK_HEIGHT;
671 static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
673 return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface);
676 static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface)
678 return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface);
681 static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface)
683 return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface);
686 static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
688 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface);
691 static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface)
693 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface);
696 static inline DdsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
698 return CONTAINING_RECORD(iface, DdsEncoder, IWICBitmapEncoder_iface);
701 static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
702 void **ppv)
704 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
705 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
707 if (!ppv) return E_INVALIDARG;
709 if (IsEqualIID(&IID_IUnknown, iid) ||
710 IsEqualIID(&IID_IWICBitmapSource, iid) ||
711 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) {
712 *ppv = &This->IWICBitmapFrameDecode_iface;
713 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) {
714 *ppv = &This->IWICDdsFrameDecode_iface;
715 } else {
716 *ppv = NULL;
717 return E_NOINTERFACE;
720 IUnknown_AddRef((IUnknown*)*ppv);
721 return S_OK;
724 static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
726 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
727 ULONG ref = InterlockedIncrement(&This->ref);
729 TRACE("(%p) refcount=%u\n", iface, ref);
731 return ref;
734 static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface)
736 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
737 ULONG ref = InterlockedDecrement(&This->ref);
739 TRACE("(%p) refcount=%u\n", iface, ref);
741 if (ref == 0) {
742 if (This->pixel_data != This->block_data) HeapFree(GetProcessHeap(), 0, This->pixel_data);
743 HeapFree(GetProcessHeap(), 0, This->block_data);
744 HeapFree(GetProcessHeap(), 0, This);
747 return ref;
750 static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
751 UINT *puiWidth, UINT *puiHeight)
753 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
755 if (!puiWidth || !puiHeight) return E_INVALIDARG;
757 *puiWidth = This->info.width;
758 *puiHeight = This->info.height;
760 TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight);
762 return S_OK;
765 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
766 WICPixelFormatGUID *pPixelFormat)
768 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
770 if (!pPixelFormat) return E_INVALIDARG;
772 *pPixelFormat = *This->info.pixel_format;
774 TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat));
776 return S_OK;
779 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
780 double *pDpiX, double *pDpiY)
782 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
784 return E_NOTIMPL;
787 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
788 IWICPalette *pIPalette)
790 FIXME("(%p,%p): stub.\n", iface, pIPalette);
792 return E_NOTIMPL;
795 static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
796 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
798 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
799 UINT bpp, frame_stride, frame_size;
800 INT x, y, width, height;
801 HRESULT hr;
803 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
805 if (!pbBuffer) return E_INVALIDARG;
807 bpp = This->info.pixel_format_bpp;
808 if (!bpp) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
810 frame_stride = This->info.width * bpp / 8;
811 frame_size = frame_stride * This->info.height;
812 if (!prc) {
813 if (cbStride < frame_stride) return E_INVALIDARG;
814 if (cbBufferSize < frame_size) return WINCODEC_ERR_INSUFFICIENTBUFFER;
815 } else {
816 x = prc->X;
817 y = prc->Y;
818 width = prc->Width;
819 height = prc->Height;
820 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
821 x + width > This->info.width ||
822 y + height > This->info.height) {
823 return E_INVALIDARG;
825 if (cbStride < width * bpp / 8) return E_INVALIDARG;
826 if (cbBufferSize < cbStride * height) return WINCODEC_ERR_INSUFFICIENTBUFFER;
829 EnterCriticalSection(&This->lock);
831 if (!This->pixel_data) {
832 if (is_compressed(This->info.format)) {
833 This->pixel_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
834 if (!This->pixel_data) {
835 hr = E_OUTOFMEMORY;
836 goto end;
838 decode_block(This->block_data, This->info.width_in_blocks * This->info.height_in_blocks, This->info.format,
839 This->info.width, This->info.height, (DWORD *)This->pixel_data);
840 } else {
841 This->pixel_data = This->block_data;
845 hr = copy_pixels(bpp, This->pixel_data, This->info.width, This->info.height, frame_stride,
846 prc, cbStride, cbBufferSize, pbBuffer);
848 end:
849 LeaveCriticalSection(&This->lock);
851 return hr;
854 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
855 IWICMetadataQueryReader **ppIMetadataQueryReader)
857 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
859 return E_NOTIMPL;
862 static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
863 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
865 FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount);
867 return E_NOTIMPL;
870 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
871 IWICBitmapSource **ppIThumbnail)
873 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
875 return E_NOTIMPL;
878 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = {
879 DdsFrameDecode_QueryInterface,
880 DdsFrameDecode_AddRef,
881 DdsFrameDecode_Release,
882 DdsFrameDecode_GetSize,
883 DdsFrameDecode_GetPixelFormat,
884 DdsFrameDecode_GetResolution,
885 DdsFrameDecode_CopyPalette,
886 DdsFrameDecode_CopyPixels,
887 DdsFrameDecode_GetMetadataQueryReader,
888 DdsFrameDecode_GetColorContexts,
889 DdsFrameDecode_GetThumbnail
892 static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface,
893 REFIID iid, void **ppv)
895 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
896 return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
899 static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface)
901 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
902 return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
905 static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface)
907 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
908 return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
911 static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface,
912 UINT *widthInBlocks, UINT *heightInBlocks)
914 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
916 if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG;
918 *widthInBlocks = This->info.width_in_blocks;
919 *heightInBlocks = This->info.height_in_blocks;
921 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks);
923 return S_OK;
926 static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface,
927 WICDdsFormatInfo *formatInfo)
929 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
931 if (!formatInfo) return E_INVALIDARG;
933 formatInfo->DxgiFormat = This->info.format;
934 formatInfo->BytesPerBlock = This->info.bytes_per_block;
935 formatInfo->BlockWidth = This->info.block_width;
936 formatInfo->BlockHeight = This->info.block_height;
938 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo,
939 formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight);
941 return S_OK;
944 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
945 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
946 BYTE *buffer)
948 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
949 int x, y, width, height;
950 UINT bytes_per_block, frame_stride, frame_size;
952 TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer);
954 if (!buffer) return E_INVALIDARG;
956 bytes_per_block = This->info.bytes_per_block;
957 frame_stride = This->info.width_in_blocks * bytes_per_block;
958 frame_size = frame_stride * This->info.height_in_blocks;
960 if (!boundsInBlocks) {
961 if (stride < frame_stride) return E_INVALIDARG;
962 if (bufferSize < frame_size) return E_INVALIDARG;
963 } else {
964 x = boundsInBlocks->X;
965 y = boundsInBlocks->Y;
966 width = boundsInBlocks->Width;
967 height = boundsInBlocks->Height;
968 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
969 x + width > This->info.width_in_blocks ||
970 y + height > This->info.height_in_blocks) {
971 return E_INVALIDARG;
973 if (stride < width * bytes_per_block) return E_INVALIDARG;
974 if (bufferSize < stride * height) return E_INVALIDARG;
977 return copy_pixels(This->info.bytes_per_block * 8, This->block_data, This->info.width_in_blocks,
978 This->info.height_in_blocks, frame_stride, boundsInBlocks, stride, bufferSize, buffer);
981 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = {
982 DdsFrameDecode_Dds_QueryInterface,
983 DdsFrameDecode_Dds_AddRef,
984 DdsFrameDecode_Dds_Release,
985 DdsFrameDecode_Dds_GetSizeInBlocks,
986 DdsFrameDecode_Dds_GetFormatInfo,
987 DdsFrameDecode_Dds_CopyBlocks
990 static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode)
992 DdsFrameDecode *result;
994 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
995 if (!result) return E_OUTOFMEMORY;
997 result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl;
998 result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl;
999 result->ref = 1;
1000 InitializeCriticalSection(&result->lock);
1001 result->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsFrameDecode.lock");
1003 *frame_decode = result;
1004 return S_OK;
1007 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1008 void **ppv)
1010 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1011 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1013 if (!ppv) return E_INVALIDARG;
1015 if (IsEqualIID(&IID_IUnknown, iid) ||
1016 IsEqualIID(&IID_IWICBitmapDecoder, iid)) {
1017 *ppv = &This->IWICBitmapDecoder_iface;
1018 } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) {
1019 *ppv = &This->IWICDdsDecoder_iface;
1020 } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) {
1021 *ppv = &This->IWICWineDecoder_iface;
1022 } else {
1023 *ppv = NULL;
1024 return E_NOINTERFACE;
1027 IUnknown_AddRef((IUnknown*)*ppv);
1028 return S_OK;
1031 static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface)
1033 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1034 ULONG ref = InterlockedIncrement(&This->ref);
1036 TRACE("(%p) refcount=%u\n", iface, ref);
1038 return ref;
1041 static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface)
1043 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1044 ULONG ref = InterlockedDecrement(&This->ref);
1046 TRACE("(%p) refcount=%u\n", iface, ref);
1048 if (ref == 0)
1050 This->lock.DebugInfo->Spare[0] = 0;
1051 DeleteCriticalSection(&This->lock);
1052 if (This->stream) IStream_Release(This->stream);
1053 HeapFree(GetProcessHeap(), 0, This);
1056 return ref;
1059 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1060 DWORD *capability)
1062 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
1064 return E_NOTIMPL;
1067 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1068 WICDecodeOptions cacheOptions)
1070 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1071 HRESULT hr;
1073 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1075 EnterCriticalSection(&This->lock);
1077 hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions);
1078 if (FAILED(hr)) goto end;
1080 if (This->info.dimension == WICDdsTextureCube ||
1081 (This->info.format != DXGI_FORMAT_BC1_UNORM &&
1082 This->info.format != DXGI_FORMAT_BC2_UNORM &&
1083 This->info.format != DXGI_FORMAT_BC3_UNORM)) {
1084 IStream_Release(pIStream);
1085 This->stream = NULL;
1086 This->initialized = FALSE;
1087 hr = WINCODEC_ERR_BADHEADER;
1090 end:
1091 LeaveCriticalSection(&This->lock);
1093 return hr;
1096 static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1097 GUID *pguidContainerFormat)
1099 TRACE("(%p,%p)\n", iface, pguidContainerFormat);
1101 memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID));
1103 return S_OK;
1106 static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1107 IWICBitmapDecoderInfo **ppIDecoderInfo)
1109 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1111 return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo);
1114 static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface,
1115 IWICPalette *pIPalette)
1117 TRACE("(%p,%p)\n", iface, pIPalette);
1119 return WINCODEC_ERR_PALETTEUNAVAILABLE;
1122 static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1123 IWICMetadataQueryReader **ppIMetadataQueryReader)
1125 if (!ppIMetadataQueryReader) return E_INVALIDARG;
1127 FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader);
1129 return E_NOTIMPL;
1132 static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface,
1133 IWICBitmapSource **ppIBitmapSource)
1135 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1137 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1140 static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1141 UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount)
1143 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount);
1145 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1148 static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1149 IWICBitmapSource **ppIThumbnail)
1151 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1153 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1156 static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1157 UINT *pCount)
1159 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1161 if (!pCount) return E_INVALIDARG;
1162 if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
1164 EnterCriticalSection(&This->lock);
1166 *pCount = This->info.frame_count;
1168 LeaveCriticalSection(&This->lock);
1170 TRACE("(%p) -> %d\n", iface, *pCount);
1172 return S_OK;
1175 static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface,
1176 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1178 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1179 UINT frame_per_texture, array_index, mip_level, slice_index, depth;
1181 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1183 if (!ppIBitmapFrame) return E_INVALIDARG;
1185 EnterCriticalSection(&This->lock);
1187 if (!This->initialized) {
1188 LeaveCriticalSection(&This->lock);
1189 return WINCODEC_ERR_WRONGSTATE;
1192 if (This->info.dimension == WICDdsTextureCube) {
1193 frame_per_texture = This->info.mip_levels;
1194 } else {
1195 frame_per_texture = This->info.frame_count / This->info.array_size;
1197 array_index = index / frame_per_texture;
1198 slice_index = index % frame_per_texture;
1199 depth = This->info.depth;
1200 mip_level = 0;
1201 while (slice_index >= depth)
1203 slice_index -= depth;
1204 mip_level++;
1205 if (depth > 1) depth /= 2;
1208 LeaveCriticalSection(&This->lock);
1210 return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame);
1213 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = {
1214 DdsDecoder_QueryInterface,
1215 DdsDecoder_AddRef,
1216 DdsDecoder_Release,
1217 DdsDecoder_QueryCapability,
1218 DdsDecoder_Initialize,
1219 DdsDecoder_GetContainerFormat,
1220 DdsDecoder_GetDecoderInfo,
1221 DdsDecoder_CopyPalette,
1222 DdsDecoder_GetMetadataQueryReader,
1223 DdsDecoder_GetPreview,
1224 DdsDecoder_GetColorContexts,
1225 DdsDecoder_GetThumbnail,
1226 DdsDecoder_GetFrameCount,
1227 DdsDecoder_GetFrame
1230 static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface,
1231 REFIID iid, void **ppv)
1233 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1234 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1237 static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface)
1239 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1240 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1243 static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface)
1245 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1246 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1249 static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface,
1250 WICDdsParameters *parameters)
1252 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1253 HRESULT hr;
1255 if (!parameters) return E_INVALIDARG;
1257 EnterCriticalSection(&This->lock);
1259 if (!This->initialized) {
1260 hr = WINCODEC_ERR_WRONGSTATE;
1261 goto end;
1264 parameters->Width = This->info.width;
1265 parameters->Height = This->info.height;
1266 parameters->Depth = This->info.depth;
1267 parameters->MipLevels = This->info.mip_levels;
1268 parameters->ArraySize = This->info.array_size;
1269 parameters->DxgiFormat = This->info.format;
1270 parameters->Dimension = This->info.dimension;
1271 parameters->AlphaMode = This->info.alpha_mode;
1273 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1274 iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1275 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1277 hr = S_OK;
1279 end:
1280 LeaveCriticalSection(&This->lock);
1282 return hr;
1285 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface,
1286 UINT arrayIndex, UINT mipLevel, UINT sliceIndex,
1287 IWICBitmapFrameDecode **bitmapFrame)
1289 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1290 HRESULT hr;
1291 LARGE_INTEGER seek;
1292 UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size;
1293 UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0;
1294 UINT bytes_per_block, bytesread, i;
1295 DdsFrameDecode *frame_decode = NULL;
1297 TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame);
1299 if (!bitmapFrame) return E_INVALIDARG;
1301 EnterCriticalSection(&This->lock);
1303 if (!This->initialized) {
1304 hr = WINCODEC_ERR_WRONGSTATE;
1305 goto end;
1308 if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) ||
1309 (arrayIndex >= This->info.array_size * 6) ||
1310 (mipLevel >= This->info.mip_levels) ||
1311 (sliceIndex >= This->info.depth)) {
1312 hr = E_INVALIDARG;
1313 goto end;
1316 if (is_compressed(This->info.format)) {
1317 block_width = DDS_BLOCK_WIDTH;
1318 block_height = DDS_BLOCK_HEIGHT;
1319 } else {
1320 block_width = 1;
1321 block_height = 1;
1323 bytes_per_block = This->info.bytes_per_block;
1324 seek.QuadPart = This->info.data_offset;
1326 width = This->info.width;
1327 height = This->info.height;
1328 depth = This->info.depth;
1329 for (i = 0; i < This->info.mip_levels; i++)
1331 width_in_blocks = (width + block_width - 1) / block_width;
1332 height_in_blocks = (height + block_height - 1) / block_height;
1333 size = width_in_blocks * height_in_blocks * bytes_per_block;
1335 if (i < mipLevel) {
1336 seek.QuadPart += size * depth;
1337 } else if (i == mipLevel){
1338 seek.QuadPart += size * sliceIndex;
1339 frame_width = width;
1340 frame_height = height;
1341 frame_width_in_blocks = width_in_blocks;
1342 frame_height_in_blocks = height_in_blocks;
1343 frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block;
1344 if (arrayIndex == 0) break;
1346 seek.QuadPart += arrayIndex * size * depth;
1348 if (width > 1) width /= 2;
1349 if (height > 1) height /= 2;
1350 if (depth > 1) depth /= 2;
1353 hr = DdsFrameDecode_CreateInstance(&frame_decode);
1354 if (hr != S_OK) goto end;
1355 frame_decode->info.width = frame_width;
1356 frame_decode->info.height = frame_height;
1357 frame_decode->info.format = This->info.format;
1358 frame_decode->info.bytes_per_block = bytes_per_block;
1359 frame_decode->info.block_width = block_width;
1360 frame_decode->info.block_height = block_height;
1361 frame_decode->info.width_in_blocks = frame_width_in_blocks;
1362 frame_decode->info.height_in_blocks = frame_height_in_blocks;
1363 frame_decode->info.pixel_format = This->info.pixel_format;
1364 frame_decode->info.pixel_format_bpp = This->info.pixel_format_bpp;
1365 frame_decode->block_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
1366 frame_decode->pixel_data = NULL;
1367 hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL);
1368 if (hr != S_OK) goto end;
1369 hr = IStream_Read(This->stream, frame_decode->block_data, frame_size, &bytesread);
1370 if (hr != S_OK || bytesread != frame_size) {
1371 hr = WINCODEC_ERR_STREAMREAD;
1372 goto end;
1374 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
1376 hr = S_OK;
1378 end:
1379 LeaveCriticalSection(&This->lock);
1381 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
1383 return hr;
1386 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = {
1387 DdsDecoder_Dds_QueryInterface,
1388 DdsDecoder_Dds_AddRef,
1389 DdsDecoder_Dds_Release,
1390 DdsDecoder_Dds_GetParameters,
1391 DdsDecoder_Dds_GetFrame
1394 static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv)
1396 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1397 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1400 static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface)
1402 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1403 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1406 static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface)
1408 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1409 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1412 static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options)
1414 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1415 DDS_HEADER_DXT10 header_dxt10;
1416 LARGE_INTEGER seek;
1417 DDS_HEADER header;
1418 ULONG bytesread;
1419 DWORD magic;
1420 HRESULT hr;
1422 TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options);
1424 EnterCriticalSection(&This->lock);
1426 if (This->initialized) {
1427 hr = WINCODEC_ERR_WRONGSTATE;
1428 goto end;
1431 seek.QuadPart = 0;
1432 hr = IStream_Seek(stream, seek, SEEK_SET, NULL);
1433 if (FAILED(hr)) goto end;
1435 hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread);
1436 if (FAILED(hr)) goto end;
1437 if (bytesread != sizeof(magic)) {
1438 hr = WINCODEC_ERR_STREAMREAD;
1439 goto end;
1441 if (magic != DDS_MAGIC) {
1442 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
1443 goto end;
1446 hr = IStream_Read(stream, &header, sizeof(header), &bytesread);
1447 if (FAILED(hr)) goto end;
1448 if (bytesread != sizeof(header)) {
1449 hr = WINCODEC_ERR_STREAMREAD;
1450 goto end;
1452 if (header.size != sizeof(header)) {
1453 hr = WINCODEC_ERR_BADHEADER;
1454 goto end;
1457 if (has_extended_header(&header)) {
1458 hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread);
1459 if (FAILED(hr)) goto end;
1460 if (bytesread != sizeof(header_dxt10)) {
1461 hr = WINCODEC_ERR_STREAMREAD;
1462 goto end;
1466 get_dds_info(&This->info, &header, &header_dxt10);
1468 This->initialized = TRUE;
1469 This->stream = stream;
1470 IStream_AddRef(stream);
1472 end:
1473 LeaveCriticalSection(&This->lock);
1475 return hr;
1478 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = {
1479 DdsDecoder_Wine_QueryInterface,
1480 DdsDecoder_Wine_AddRef,
1481 DdsDecoder_Wine_Release,
1482 DdsDecoder_Wine_Initialize
1485 HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv)
1487 DdsDecoder *This;
1488 HRESULT ret;
1490 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1492 *ppv = NULL;
1494 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder));
1495 if (!This) return E_OUTOFMEMORY;
1497 This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl;
1498 This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl;
1499 This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl;
1500 This->ref = 1;
1501 This->initialized = FALSE;
1502 This->stream = NULL;
1503 InitializeCriticalSection(&This->lock);
1504 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock");
1506 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1507 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1509 return ret;
1512 static HRESULT WINAPI DdsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1513 void **ppv)
1515 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1516 FIXME("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1518 if (!ppv) return E_INVALIDARG;
1520 if (IsEqualIID(&IID_IUnknown, iid) ||
1521 IsEqualIID(&IID_IWICBitmapEncoder, iid)) {
1522 *ppv = &This->IWICBitmapEncoder_iface;
1524 else {
1525 *ppv = NULL;
1526 return E_NOINTERFACE;
1529 IUnknown_AddRef((IUnknown*)*ppv);
1530 return S_OK;
1533 static ULONG WINAPI DdsEncoder_AddRef(IWICBitmapEncoder *iface)
1535 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1536 ULONG ref = InterlockedIncrement(&This->ref);
1538 TRACE("(%p) refcount=%u\n", iface, ref);
1540 return ref;
1543 static ULONG WINAPI DdsEncoder_Release(IWICBitmapEncoder *iface)
1545 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1546 ULONG ref = InterlockedDecrement(&This->ref);
1548 TRACE("(%p) refcount=%u\n", iface, ref);
1550 if (ref == 0) {
1551 This->lock.DebugInfo->Spare[0] = 0;
1552 DeleteCriticalSection(&This->lock);
1553 if (This->stream) IStream_Release(This->stream);
1554 HeapFree(GetProcessHeap(), 0, This);
1557 return ref;
1560 static HRESULT WINAPI DdsEncoder_Initialize(IWICBitmapEncoder *iface,
1561 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1563 FIXME("(%p,%p,%u): stub\n", iface, pIStream, cacheOption);
1564 return E_NOTIMPL;
1567 static HRESULT WINAPI DdsEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
1569 TRACE("(%p,%p)\n", iface, format);
1571 if (!format)
1572 return E_INVALIDARG;
1574 memcpy(format, &GUID_ContainerFormatDds, sizeof(*format));
1575 return S_OK;
1578 static HRESULT WINAPI DdsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
1580 IWICComponentInfo *comp_info;
1581 HRESULT hr;
1583 TRACE("%p,%p\n", iface, info);
1585 if (!info) return E_INVALIDARG;
1587 hr = CreateComponentInfo(&CLSID_WICDdsEncoder, &comp_info);
1588 if (hr == S_OK) {
1589 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
1590 IWICComponentInfo_Release(comp_info);
1592 return hr;
1595 static HRESULT WINAPI DdsEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1596 UINT cCount, IWICColorContext **ppIColorContext)
1598 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1599 return E_NOTIMPL;
1602 static HRESULT WINAPI DdsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
1604 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1605 HRESULT hr;
1607 TRACE("(%p,%p)\n", iface, palette);
1609 EnterCriticalSection(&This->lock);
1611 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
1613 LeaveCriticalSection(&This->lock);
1615 return hr;
1618 static HRESULT WINAPI DdsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1620 TRACE("(%p,%p)\n", iface, pIThumbnail);
1621 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1624 static HRESULT WINAPI DdsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1626 TRACE("(%p,%p)\n", iface, pIPreview);
1627 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1630 static HRESULT WINAPI DdsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1631 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1633 FIXME("(%p,%p,%p): stub\n", iface, ppIFrameEncode, ppIEncoderOptions);
1634 return E_NOTIMPL;
1637 static HRESULT WINAPI DdsEncoder_Commit(IWICBitmapEncoder *iface)
1639 FIXME("(%p): stub\n", iface);
1640 return E_NOTIMPL;
1643 static HRESULT WINAPI DdsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1644 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1646 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1647 return E_NOTIMPL;
1650 static const IWICBitmapEncoderVtbl DdsEncoder_Vtbl = {
1651 DdsEncoder_QueryInterface,
1652 DdsEncoder_AddRef,
1653 DdsEncoder_Release,
1654 DdsEncoder_Initialize,
1655 DdsEncoder_GetContainerFormat,
1656 DdsEncoder_GetEncoderInfo,
1657 DdsEncoder_SetColorContexts,
1658 DdsEncoder_SetPalette,
1659 DdsEncoder_SetThumbnail,
1660 DdsEncoder_SetPreview,
1661 DdsEncoder_CreateNewFrame,
1662 DdsEncoder_Commit,
1663 DdsEncoder_GetMetadataQueryWriter
1666 HRESULT DdsEncoder_CreateInstance( REFIID iid, void **ppv)
1668 DdsEncoder *This;
1669 HRESULT ret;
1671 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1673 *ppv = NULL;
1675 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsEncoder));
1676 if (!This) return E_OUTOFMEMORY;
1678 This->IWICBitmapEncoder_iface.lpVtbl = &DdsEncoder_Vtbl;
1679 This->ref = 1;
1680 This->stream = NULL;
1681 This->frame_count = 0;
1682 This->uncommitted_frame = FALSE;
1683 This->committed = FALSE;
1684 InitializeCriticalSection(&This->lock);
1685 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsEncoder.lock");
1687 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
1688 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1690 return ret;