windowscodecs: Add stub for IWICDdsEncoder.
[wine.git] / dlls / windowscodecs / ddsformat.c
bloba102d4883cd5cf0ffea66addf37624ce93b86af4
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 IWICDdsEncoder IWICDdsEncoder_iface;
165 LONG ref;
166 CRITICAL_SECTION lock;
167 IStream *stream;
168 UINT frame_count;
169 BOOL uncommitted_frame;
170 BOOL committed;
171 } DdsEncoder;
173 typedef struct DdsFrameEncode {
174 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
175 LONG ref;
176 DdsEncoder *parent;
177 BOOL initialized;
178 BOOL frame_created;
179 UINT width;
180 UINT height;
181 double dpi_x;
182 double dpi_y;
183 } DdsFrameEncode;
185 static struct dds_format {
186 DDS_PIXELFORMAT pixel_format;
187 const GUID *wic_format;
188 UINT wic_format_bpp;
189 DXGI_FORMAT dxgi_format;
190 } dds_format_table[] = {
191 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 },
192 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC1_UNORM },
193 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 },
194 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC2_UNORM },
195 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 },
196 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC2_UNORM },
197 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 },
198 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC3_UNORM },
199 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 },
200 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC3_UNORM },
201 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 },
202 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
203 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 },
204 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_SNORM },
205 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 },
206 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
207 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 },
208 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_SNORM },
209 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 },
210 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
211 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 },
212 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
213 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 },
214 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_R8G8_B8G8_UNORM },
215 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 },
216 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_G8R8_G8B8_UNORM },
217 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 },
218 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN },
219 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 },
220 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
221 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 },
222 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_SNORM },
223 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 },
224 &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
225 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 },
226 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_FLOAT },
227 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 },
228 &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
229 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 },
230 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
231 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 },
232 &GUID_WICPixelFormatUndefined, 32, DXGI_FORMAT_R32G32_FLOAT },
233 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 },
234 &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
235 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 },
236 &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
237 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0 },
238 &GUID_WICPixelFormat32bppRGB, 32, DXGI_FORMAT_UNKNOWN },
239 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 },
240 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
241 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 },
242 &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
243 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
244 * For "correct" one, the RGB masks should be 0x3FF,0xFFC00,0x3FF00000.
245 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
246 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF00000,0xFFC00,0x3FF,0xC0000000 },
247 &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
248 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 },
249 &GUID_WICPixelFormat32bppRGBA1010102, 32, DXGI_FORMAT_UNKNOWN },
250 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 },
251 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_UNORM },
252 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 },
253 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
254 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0xFF0000,0x00FF00,0x0000FF,0 },
255 &GUID_WICPixelFormat24bppBGR, 24, DXGI_FORMAT_UNKNOWN },
256 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0x0000FF,0x00FF00,0xFF0000,0 },
257 &GUID_WICPixelFormat24bppRGB, 24, DXGI_FORMAT_UNKNOWN },
258 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 },
259 &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
260 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0 },
261 &GUID_WICPixelFormat16bppBGR555, 16, DXGI_FORMAT_UNKNOWN },
262 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 },
263 &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
264 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 },
265 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_B4G4R4A4_UNORM },
266 { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF },
267 &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
268 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 },
269 &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
270 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 },
271 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R8G8_UNORM },
272 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 },
273 &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
274 { { 0 }, &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
275 { { 0 }, &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
276 { { 0 }, &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
277 { { 0 }, &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
278 { { 0 }, &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
279 { { 0 }, &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
280 { { 0 }, &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
281 { { 0 }, &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
282 { { 0 }, &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
283 { { 0 }, &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
284 { { 0 }, &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
285 { { 0 }, &GUID_WICPixelFormat32bppRGBE, 32, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
286 { { 0 }, &GUID_WICPixelFormat32bppRGBA1010102XR, 32, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },
287 { { 0 }, &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
288 { { 0 }, &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
289 { { 0 }, &GUID_WICPixelFormat96bppRGBFloat, 96, DXGI_FORMAT_R32G32B32_FLOAT },
290 { { 0 }, &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
291 { { 0 }, &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN }
294 static DXGI_FORMAT compressed_formats[] = {
295 DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB,
296 DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB,
297 DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB,
298 DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM,
299 DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM,
300 DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16,
301 DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB
304 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **);
306 static DWORD rgb565_to_argb(WORD color, BYTE alpha)
308 return MAKE_ARGB(alpha, (GET_RGB565_R(color) * 0xFF + 0x0F) / 0x1F,
309 (GET_RGB565_G(color) * 0xFF + 0x1F) / 0x3F,
310 (GET_RGB565_B(color) * 0xFF + 0x0F) / 0x1F);
313 static inline BOOL has_extended_header(DDS_HEADER *header)
315 return (header->ddspf.flags & DDPF_FOURCC) &&
316 (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'));
319 static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
321 if (header_dxt10) {
322 if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube;
323 switch (header_dxt10->resourceDimension)
325 case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D;
326 case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D;
327 case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D;
328 default: return WICDdsTexture2D;
330 } else {
331 if (header->caps2 & DDSCAPS2_CUBEMAP) {
332 return WICDdsTextureCube;
333 } else if (header->caps2 & DDSCAPS2_VOLUME) {
334 return WICDdsTexture3D;
335 } else {
336 return WICDdsTexture2D;
341 static struct dds_format *get_dds_format(DDS_PIXELFORMAT *pixel_format)
343 UINT i;
345 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
347 if ((pixel_format->flags & dds_format_table[i].pixel_format.flags) &&
348 (pixel_format->fourCC == dds_format_table[i].pixel_format.fourCC) &&
349 (pixel_format->rgbBitCount == dds_format_table[i].pixel_format.rgbBitCount) &&
350 (pixel_format->rBitMask == dds_format_table[i].pixel_format.rBitMask) &&
351 (pixel_format->gBitMask == dds_format_table[i].pixel_format.gBitMask) &&
352 (pixel_format->bBitMask == dds_format_table[i].pixel_format.bBitMask) &&
353 (pixel_format->aBitMask == dds_format_table[i].pixel_format.aBitMask))
354 return dds_format_table + i;
357 return dds_format_table + ARRAY_SIZE(dds_format_table) - 1;
360 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
362 switch (fourcc)
364 case MAKEFOURCC('D', 'X', 'T', '1'):
365 case MAKEFOURCC('D', 'X', 'T', '2'):
366 case MAKEFOURCC('D', 'X', 'T', '4'):
367 return WICDdsAlphaModePremultiplied;
368 default:
369 return WICDdsAlphaModeUnknown;
373 static UINT get_bytes_per_block_from_format(DXGI_FORMAT format)
375 /* for uncompressed format, return bytes per pixel*/
376 switch (format)
378 case DXGI_FORMAT_R8_TYPELESS:
379 case DXGI_FORMAT_R8_UNORM:
380 case DXGI_FORMAT_R8_UINT:
381 case DXGI_FORMAT_R8_SNORM:
382 case DXGI_FORMAT_R8_SINT:
383 case DXGI_FORMAT_A8_UNORM:
384 return 1;
385 case DXGI_FORMAT_R8G8_TYPELESS:
386 case DXGI_FORMAT_R8G8_UNORM:
387 case DXGI_FORMAT_R8G8_UINT:
388 case DXGI_FORMAT_R8G8_SNORM:
389 case DXGI_FORMAT_R8G8_SINT:
390 case DXGI_FORMAT_R16_TYPELESS:
391 case DXGI_FORMAT_R16_FLOAT:
392 case DXGI_FORMAT_D16_UNORM:
393 case DXGI_FORMAT_R16_UNORM:
394 case DXGI_FORMAT_R16_UINT:
395 case DXGI_FORMAT_R16_SNORM:
396 case DXGI_FORMAT_R16_SINT:
397 case DXGI_FORMAT_B5G6R5_UNORM:
398 case DXGI_FORMAT_B5G5R5A1_UNORM:
399 case DXGI_FORMAT_B4G4R4A4_UNORM:
400 return 2;
401 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
402 case DXGI_FORMAT_R10G10B10A2_UNORM:
403 case DXGI_FORMAT_R10G10B10A2_UINT:
404 case DXGI_FORMAT_R11G11B10_FLOAT:
405 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
406 case DXGI_FORMAT_R8G8B8A8_UNORM:
407 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
408 case DXGI_FORMAT_R8G8B8A8_UINT:
409 case DXGI_FORMAT_R8G8B8A8_SNORM:
410 case DXGI_FORMAT_R8G8B8A8_SINT:
411 case DXGI_FORMAT_R16G16_TYPELESS:
412 case DXGI_FORMAT_R16G16_FLOAT:
413 case DXGI_FORMAT_R16G16_UNORM:
414 case DXGI_FORMAT_R16G16_UINT:
415 case DXGI_FORMAT_R16G16_SNORM:
416 case DXGI_FORMAT_R16G16_SINT:
417 case DXGI_FORMAT_R32_TYPELESS:
418 case DXGI_FORMAT_D32_FLOAT:
419 case DXGI_FORMAT_R32_FLOAT:
420 case DXGI_FORMAT_R32_UINT:
421 case DXGI_FORMAT_R32_SINT:
422 case DXGI_FORMAT_R24G8_TYPELESS:
423 case DXGI_FORMAT_D24_UNORM_S8_UINT:
424 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
425 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
426 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
427 case DXGI_FORMAT_R8G8_B8G8_UNORM:
428 case DXGI_FORMAT_G8R8_G8B8_UNORM:
429 case DXGI_FORMAT_B8G8R8A8_UNORM:
430 case DXGI_FORMAT_B8G8R8X8_UNORM:
431 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
432 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
433 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
434 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
435 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
436 return 4;
437 case DXGI_FORMAT_BC1_UNORM:
438 case DXGI_FORMAT_BC1_TYPELESS:
439 case DXGI_FORMAT_BC1_UNORM_SRGB:
440 case DXGI_FORMAT_BC4_TYPELESS:
441 case DXGI_FORMAT_BC4_UNORM:
442 case DXGI_FORMAT_BC4_SNORM:
443 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
444 case DXGI_FORMAT_R16G16B16A16_FLOAT:
445 case DXGI_FORMAT_R16G16B16A16_UNORM:
446 case DXGI_FORMAT_R16G16B16A16_UINT:
447 case DXGI_FORMAT_R16G16B16A16_SNORM:
448 case DXGI_FORMAT_R16G16B16A16_SINT:
449 case DXGI_FORMAT_R32G32_TYPELESS:
450 case DXGI_FORMAT_R32G32_FLOAT:
451 case DXGI_FORMAT_R32G32_UINT:
452 case DXGI_FORMAT_R32G32_SINT:
453 case DXGI_FORMAT_R32G8X24_TYPELESS:
454 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
455 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
456 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
457 return 8;
458 case DXGI_FORMAT_R32G32B32_TYPELESS:
459 case DXGI_FORMAT_R32G32B32_FLOAT:
460 case DXGI_FORMAT_R32G32B32_UINT:
461 case DXGI_FORMAT_R32G32B32_SINT:
462 return 12;
463 case DXGI_FORMAT_BC2_UNORM:
464 case DXGI_FORMAT_BC2_TYPELESS:
465 case DXGI_FORMAT_BC2_UNORM_SRGB:
466 case DXGI_FORMAT_BC3_UNORM:
467 case DXGI_FORMAT_BC3_TYPELESS:
468 case DXGI_FORMAT_BC3_UNORM_SRGB:
469 case DXGI_FORMAT_BC5_TYPELESS:
470 case DXGI_FORMAT_BC5_UNORM:
471 case DXGI_FORMAT_BC5_SNORM:
472 case DXGI_FORMAT_BC6H_TYPELESS:
473 case DXGI_FORMAT_BC6H_UF16:
474 case DXGI_FORMAT_BC6H_SF16:
475 case DXGI_FORMAT_BC7_TYPELESS:
476 case DXGI_FORMAT_BC7_UNORM:
477 case DXGI_FORMAT_BC7_UNORM_SRGB:
478 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
479 case DXGI_FORMAT_R32G32B32A32_FLOAT:
480 case DXGI_FORMAT_R32G32B32A32_UINT:
481 case DXGI_FORMAT_R32G32B32A32_SINT:
482 return 16;
483 default:
484 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
485 return 0;
489 static const GUID *dxgi_format_to_wic_format(DXGI_FORMAT dxgi_format)
491 UINT i;
492 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
494 if (dds_format_table[i].pixel_format.size == 0 &&
495 dds_format_table[i].dxgi_format == dxgi_format)
496 return dds_format_table[i].wic_format;
498 return &GUID_WICPixelFormatUndefined;
501 static BOOL is_compressed(DXGI_FORMAT format)
503 UINT i;
505 for (i = 0; i < ARRAY_SIZE(compressed_formats); i++)
507 if (format == compressed_formats[i]) return TRUE;
509 return FALSE;
512 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
514 int i;
515 UINT depth;
516 struct dds_format *format_info;
518 info->width = header->width;
519 info->height = header->height;
520 info->depth = 1;
521 info->mip_levels = 1;
522 info->array_size = 1;
523 if (header->depth) info->depth = header->depth;
524 if (header->mipMapCount) info->mip_levels = header->mipMapCount;
526 if (has_extended_header(header)) {
527 if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize;
528 info->format = header_dxt10->dxgiFormat;
529 info->dimension = get_dimension(NULL, header_dxt10);
530 info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008;
531 info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10);
532 if (is_compressed(info->format)) {
533 info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ?
534 &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA;
535 info->pixel_format_bpp = 32;
536 } else {
537 info->pixel_format = dxgi_format_to_wic_format(info->format);
538 info->pixel_format_bpp = get_bytes_per_block_from_format(info->format) * 8;
540 } else {
541 format_info = get_dds_format(&header->ddspf);
542 info->format = format_info->dxgi_format;
543 info->dimension = get_dimension(header, NULL);
544 info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC);
545 info->data_offset = sizeof(DWORD) + sizeof(*header);
546 info->pixel_format = format_info->wic_format;
547 info->pixel_format_bpp = format_info->wic_format_bpp;
550 if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) {
551 info->bytes_per_block = header->ddspf.rgbBitCount / 8;
552 } else {
553 info->bytes_per_block = get_bytes_per_block_from_format(info->format);
556 /* get frame count */
558 if (info->depth == 1) {
559 info->frame_count = info->array_size * info->mip_levels;
560 } else {
561 info->frame_count = 0;
562 depth = info->depth;
563 for (i = 0; i < info->mip_levels; i++)
565 info->frame_count += depth;
566 if (depth > 1) depth /= 2;
568 info->frame_count *= info->array_size;
570 if (info->dimension == WICDdsTextureCube) info->frame_count *= 6;
573 static void decode_block(const BYTE *block_data, UINT block_count, DXGI_FORMAT format,
574 UINT width, UINT height, DWORD *buffer)
576 const BYTE *block, *color_indices, *alpha_indices, *alpha_table;
577 int i, j, x, y, block_x, block_y, color_index, alpha_index;
578 int block_size, color_offset, color_indices_offset;
579 WORD color[4], color_value = 0;
580 BYTE alpha[8], alpha_value = 0;
582 if (format == DXGI_FORMAT_BC1_UNORM) {
583 block_size = 8;
584 color_offset = 0;
585 color_indices_offset = 4;
586 } else {
587 block_size = 16;
588 color_offset = 8;
589 color_indices_offset = 12;
591 block_x = 0;
592 block_y = 0;
594 for (i = 0; i < block_count; i++)
596 block = block_data + i * block_size;
598 color[0] = *((WORD *)(block + color_offset));
599 color[1] = *((WORD *)(block + color_offset + 2));
600 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) * 2 + GET_RGB565_R(color[1]) + 1) / 3),
601 ((GET_RGB565_G(color[0]) * 2 + GET_RGB565_G(color[1]) + 1) / 3),
602 ((GET_RGB565_B(color[0]) * 2 + GET_RGB565_B(color[1]) + 1) / 3));
603 color[3] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) * 2 + 1) / 3),
604 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) * 2 + 1) / 3),
605 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) * 2 + 1) / 3));
607 switch (format)
609 case DXGI_FORMAT_BC1_UNORM:
610 if (color[0] <= color[1]) {
611 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) + 1) / 2),
612 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) + 1) / 2),
613 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) + 1) / 2));
614 color[3] = 0;
616 break;
617 case DXGI_FORMAT_BC2_UNORM:
618 alpha_table = block;
619 break;
620 case DXGI_FORMAT_BC3_UNORM:
621 alpha[0] = *block;
622 alpha[1] = *(block + 1);
623 if (alpha[0] > alpha[1]) {
624 for (j = 2; j < 8; j++)
626 alpha[j] = (BYTE)((alpha[0] * (8 - j) + alpha[1] * (j - 1) + 3) / 7);
628 } else {
629 for (j = 2; j < 6; j++)
631 alpha[j] = (BYTE)((alpha[0] * (6 - j) + alpha[1] * (j - 1) + 2) / 5);
633 alpha[6] = 0;
634 alpha[7] = 0xFF;
636 alpha_indices = block + 2;
637 break;
638 default:
639 break;
642 color_indices = block + color_indices_offset;
643 for (j = 0; j < 16; j++)
645 x = block_x + j % 4;
646 y = block_y + j / 4;
647 if (x >= width || y >= height) continue;
649 color_index = (color_indices[j / 4] >> ((j % 4) * 2)) & 0x3;
650 color_value = color[color_index];
652 switch (format)
654 case DXGI_FORMAT_BC1_UNORM:
655 if ((color[0] <= color[1]) && !color_value) {
656 color_value = 0;
657 alpha_value = 0;
658 } else {
659 alpha_value = 0xFF;
661 break;
662 case DXGI_FORMAT_BC2_UNORM:
663 alpha_value = (alpha_table[j / 2] >> (j % 2) * 4) & 0xF;
664 alpha_value = (BYTE)((alpha_value * 0xFF + 0x7)/ 0xF);
665 break;
666 case DXGI_FORMAT_BC3_UNORM:
667 alpha_index = (*((DWORD *)(alpha_indices + (j / 8) * 3)) >> ((j % 8) * 3)) & 0x7;
668 alpha_value = alpha[alpha_index];
669 break;
670 default:
671 break;
673 buffer[x + y * width] = rgb565_to_argb(color_value, alpha_value);
676 block_x += DDS_BLOCK_WIDTH;
677 if (block_x >= width) {
678 block_x = 0;
679 block_y += DDS_BLOCK_HEIGHT;
684 static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
686 return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface);
689 static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface)
691 return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface);
694 static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface)
696 return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface);
699 static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
701 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface);
704 static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface)
706 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface);
709 static inline DdsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
711 return CONTAINING_RECORD(iface, DdsEncoder, IWICBitmapEncoder_iface);
714 static inline DdsEncoder *impl_from_IWICDdsEncoder(IWICDdsEncoder *iface)
716 return CONTAINING_RECORD(iface, DdsEncoder, IWICDdsEncoder_iface);
719 static inline DdsFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
721 return CONTAINING_RECORD(iface, DdsFrameEncode, IWICBitmapFrameEncode_iface);
724 static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
725 void **ppv)
727 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
728 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
730 if (!ppv) return E_INVALIDARG;
732 if (IsEqualIID(&IID_IUnknown, iid) ||
733 IsEqualIID(&IID_IWICBitmapSource, iid) ||
734 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) {
735 *ppv = &This->IWICBitmapFrameDecode_iface;
736 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) {
737 *ppv = &This->IWICDdsFrameDecode_iface;
738 } else {
739 *ppv = NULL;
740 return E_NOINTERFACE;
743 IUnknown_AddRef((IUnknown*)*ppv);
744 return S_OK;
747 static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
749 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
750 ULONG ref = InterlockedIncrement(&This->ref);
752 TRACE("(%p) refcount=%u\n", iface, ref);
754 return ref;
757 static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface)
759 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
760 ULONG ref = InterlockedDecrement(&This->ref);
762 TRACE("(%p) refcount=%u\n", iface, ref);
764 if (ref == 0) {
765 if (This->pixel_data != This->block_data) HeapFree(GetProcessHeap(), 0, This->pixel_data);
766 HeapFree(GetProcessHeap(), 0, This->block_data);
767 HeapFree(GetProcessHeap(), 0, This);
770 return ref;
773 static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
774 UINT *puiWidth, UINT *puiHeight)
776 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
778 if (!puiWidth || !puiHeight) return E_INVALIDARG;
780 *puiWidth = This->info.width;
781 *puiHeight = This->info.height;
783 TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight);
785 return S_OK;
788 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
789 WICPixelFormatGUID *pPixelFormat)
791 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
793 if (!pPixelFormat) return E_INVALIDARG;
795 *pPixelFormat = *This->info.pixel_format;
797 TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat));
799 return S_OK;
802 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
803 double *pDpiX, double *pDpiY)
805 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
807 return E_NOTIMPL;
810 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
811 IWICPalette *pIPalette)
813 FIXME("(%p,%p): stub.\n", iface, pIPalette);
815 return E_NOTIMPL;
818 static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
819 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
821 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
822 UINT bpp, frame_stride, frame_size;
823 INT x, y, width, height;
824 HRESULT hr;
826 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
828 if (!pbBuffer) return E_INVALIDARG;
830 bpp = This->info.pixel_format_bpp;
831 if (!bpp) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
833 frame_stride = This->info.width * bpp / 8;
834 frame_size = frame_stride * This->info.height;
835 if (!prc) {
836 if (cbStride < frame_stride) return E_INVALIDARG;
837 if (cbBufferSize < frame_size) return WINCODEC_ERR_INSUFFICIENTBUFFER;
838 } else {
839 x = prc->X;
840 y = prc->Y;
841 width = prc->Width;
842 height = prc->Height;
843 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
844 x + width > This->info.width ||
845 y + height > This->info.height) {
846 return E_INVALIDARG;
848 if (cbStride < width * bpp / 8) return E_INVALIDARG;
849 if (cbBufferSize < cbStride * height) return WINCODEC_ERR_INSUFFICIENTBUFFER;
852 EnterCriticalSection(&This->lock);
854 if (!This->pixel_data) {
855 if (is_compressed(This->info.format)) {
856 This->pixel_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
857 if (!This->pixel_data) {
858 hr = E_OUTOFMEMORY;
859 goto end;
861 decode_block(This->block_data, This->info.width_in_blocks * This->info.height_in_blocks, This->info.format,
862 This->info.width, This->info.height, (DWORD *)This->pixel_data);
863 } else {
864 This->pixel_data = This->block_data;
868 hr = copy_pixels(bpp, This->pixel_data, This->info.width, This->info.height, frame_stride,
869 prc, cbStride, cbBufferSize, pbBuffer);
871 end:
872 LeaveCriticalSection(&This->lock);
874 return hr;
877 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
878 IWICMetadataQueryReader **ppIMetadataQueryReader)
880 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
882 return E_NOTIMPL;
885 static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
886 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
888 FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount);
890 return E_NOTIMPL;
893 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
894 IWICBitmapSource **ppIThumbnail)
896 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
898 return E_NOTIMPL;
901 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = {
902 DdsFrameDecode_QueryInterface,
903 DdsFrameDecode_AddRef,
904 DdsFrameDecode_Release,
905 DdsFrameDecode_GetSize,
906 DdsFrameDecode_GetPixelFormat,
907 DdsFrameDecode_GetResolution,
908 DdsFrameDecode_CopyPalette,
909 DdsFrameDecode_CopyPixels,
910 DdsFrameDecode_GetMetadataQueryReader,
911 DdsFrameDecode_GetColorContexts,
912 DdsFrameDecode_GetThumbnail
915 static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface,
916 REFIID iid, void **ppv)
918 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
919 return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
922 static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface)
924 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
925 return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
928 static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface)
930 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
931 return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
934 static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface,
935 UINT *widthInBlocks, UINT *heightInBlocks)
937 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
939 if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG;
941 *widthInBlocks = This->info.width_in_blocks;
942 *heightInBlocks = This->info.height_in_blocks;
944 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks);
946 return S_OK;
949 static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface,
950 WICDdsFormatInfo *formatInfo)
952 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
954 if (!formatInfo) return E_INVALIDARG;
956 formatInfo->DxgiFormat = This->info.format;
957 formatInfo->BytesPerBlock = This->info.bytes_per_block;
958 formatInfo->BlockWidth = This->info.block_width;
959 formatInfo->BlockHeight = This->info.block_height;
961 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo,
962 formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight);
964 return S_OK;
967 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
968 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
969 BYTE *buffer)
971 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
972 int x, y, width, height;
973 UINT bytes_per_block, frame_stride, frame_size;
975 TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer);
977 if (!buffer) return E_INVALIDARG;
979 bytes_per_block = This->info.bytes_per_block;
980 frame_stride = This->info.width_in_blocks * bytes_per_block;
981 frame_size = frame_stride * This->info.height_in_blocks;
983 if (!boundsInBlocks) {
984 if (stride < frame_stride) return E_INVALIDARG;
985 if (bufferSize < frame_size) return E_INVALIDARG;
986 } else {
987 x = boundsInBlocks->X;
988 y = boundsInBlocks->Y;
989 width = boundsInBlocks->Width;
990 height = boundsInBlocks->Height;
991 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
992 x + width > This->info.width_in_blocks ||
993 y + height > This->info.height_in_blocks) {
994 return E_INVALIDARG;
996 if (stride < width * bytes_per_block) return E_INVALIDARG;
997 if (bufferSize < stride * height) return E_INVALIDARG;
1000 return copy_pixels(This->info.bytes_per_block * 8, This->block_data, This->info.width_in_blocks,
1001 This->info.height_in_blocks, frame_stride, boundsInBlocks, stride, bufferSize, buffer);
1004 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = {
1005 DdsFrameDecode_Dds_QueryInterface,
1006 DdsFrameDecode_Dds_AddRef,
1007 DdsFrameDecode_Dds_Release,
1008 DdsFrameDecode_Dds_GetSizeInBlocks,
1009 DdsFrameDecode_Dds_GetFormatInfo,
1010 DdsFrameDecode_Dds_CopyBlocks
1013 static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode)
1015 DdsFrameDecode *result;
1017 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
1018 if (!result) return E_OUTOFMEMORY;
1020 result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl;
1021 result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl;
1022 result->ref = 1;
1023 InitializeCriticalSection(&result->lock);
1024 result->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsFrameDecode.lock");
1026 *frame_decode = result;
1027 return S_OK;
1030 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1031 void **ppv)
1033 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1034 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1036 if (!ppv) return E_INVALIDARG;
1038 if (IsEqualIID(&IID_IUnknown, iid) ||
1039 IsEqualIID(&IID_IWICBitmapDecoder, iid)) {
1040 *ppv = &This->IWICBitmapDecoder_iface;
1041 } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) {
1042 *ppv = &This->IWICDdsDecoder_iface;
1043 } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) {
1044 *ppv = &This->IWICWineDecoder_iface;
1045 } else {
1046 *ppv = NULL;
1047 return E_NOINTERFACE;
1050 IUnknown_AddRef((IUnknown*)*ppv);
1051 return S_OK;
1054 static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface)
1056 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1057 ULONG ref = InterlockedIncrement(&This->ref);
1059 TRACE("(%p) refcount=%u\n", iface, ref);
1061 return ref;
1064 static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface)
1066 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1067 ULONG ref = InterlockedDecrement(&This->ref);
1069 TRACE("(%p) refcount=%u\n", iface, ref);
1071 if (ref == 0)
1073 This->lock.DebugInfo->Spare[0] = 0;
1074 DeleteCriticalSection(&This->lock);
1075 if (This->stream) IStream_Release(This->stream);
1076 HeapFree(GetProcessHeap(), 0, This);
1079 return ref;
1082 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1083 DWORD *capability)
1085 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
1087 return E_NOTIMPL;
1090 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1091 WICDecodeOptions cacheOptions)
1093 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1094 HRESULT hr;
1096 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1098 EnterCriticalSection(&This->lock);
1100 hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions);
1101 if (FAILED(hr)) goto end;
1103 if (This->info.dimension == WICDdsTextureCube ||
1104 (This->info.format != DXGI_FORMAT_BC1_UNORM &&
1105 This->info.format != DXGI_FORMAT_BC2_UNORM &&
1106 This->info.format != DXGI_FORMAT_BC3_UNORM)) {
1107 IStream_Release(pIStream);
1108 This->stream = NULL;
1109 This->initialized = FALSE;
1110 hr = WINCODEC_ERR_BADHEADER;
1113 end:
1114 LeaveCriticalSection(&This->lock);
1116 return hr;
1119 static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1120 GUID *pguidContainerFormat)
1122 TRACE("(%p,%p)\n", iface, pguidContainerFormat);
1124 memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID));
1126 return S_OK;
1129 static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1130 IWICBitmapDecoderInfo **ppIDecoderInfo)
1132 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1134 return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo);
1137 static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface,
1138 IWICPalette *pIPalette)
1140 TRACE("(%p,%p)\n", iface, pIPalette);
1142 return WINCODEC_ERR_PALETTEUNAVAILABLE;
1145 static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1146 IWICMetadataQueryReader **ppIMetadataQueryReader)
1148 if (!ppIMetadataQueryReader) return E_INVALIDARG;
1150 FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader);
1152 return E_NOTIMPL;
1155 static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface,
1156 IWICBitmapSource **ppIBitmapSource)
1158 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1160 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1163 static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1164 UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount)
1166 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount);
1168 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1171 static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1172 IWICBitmapSource **ppIThumbnail)
1174 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1176 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1179 static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1180 UINT *pCount)
1182 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1184 if (!pCount) return E_INVALIDARG;
1185 if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
1187 EnterCriticalSection(&This->lock);
1189 *pCount = This->info.frame_count;
1191 LeaveCriticalSection(&This->lock);
1193 TRACE("(%p) -> %d\n", iface, *pCount);
1195 return S_OK;
1198 static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface,
1199 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1201 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1202 UINT frame_per_texture, array_index, mip_level, slice_index, depth;
1204 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1206 if (!ppIBitmapFrame) return E_INVALIDARG;
1208 EnterCriticalSection(&This->lock);
1210 if (!This->initialized) {
1211 LeaveCriticalSection(&This->lock);
1212 return WINCODEC_ERR_WRONGSTATE;
1215 if (This->info.dimension == WICDdsTextureCube) {
1216 frame_per_texture = This->info.mip_levels;
1217 } else {
1218 frame_per_texture = This->info.frame_count / This->info.array_size;
1220 array_index = index / frame_per_texture;
1221 slice_index = index % frame_per_texture;
1222 depth = This->info.depth;
1223 mip_level = 0;
1224 while (slice_index >= depth)
1226 slice_index -= depth;
1227 mip_level++;
1228 if (depth > 1) depth /= 2;
1231 LeaveCriticalSection(&This->lock);
1233 return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame);
1236 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = {
1237 DdsDecoder_QueryInterface,
1238 DdsDecoder_AddRef,
1239 DdsDecoder_Release,
1240 DdsDecoder_QueryCapability,
1241 DdsDecoder_Initialize,
1242 DdsDecoder_GetContainerFormat,
1243 DdsDecoder_GetDecoderInfo,
1244 DdsDecoder_CopyPalette,
1245 DdsDecoder_GetMetadataQueryReader,
1246 DdsDecoder_GetPreview,
1247 DdsDecoder_GetColorContexts,
1248 DdsDecoder_GetThumbnail,
1249 DdsDecoder_GetFrameCount,
1250 DdsDecoder_GetFrame
1253 static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface,
1254 REFIID iid, void **ppv)
1256 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1257 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1260 static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface)
1262 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1263 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1266 static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface)
1268 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1269 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1272 static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface,
1273 WICDdsParameters *parameters)
1275 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1276 HRESULT hr;
1278 if (!parameters) return E_INVALIDARG;
1280 EnterCriticalSection(&This->lock);
1282 if (!This->initialized) {
1283 hr = WINCODEC_ERR_WRONGSTATE;
1284 goto end;
1287 parameters->Width = This->info.width;
1288 parameters->Height = This->info.height;
1289 parameters->Depth = This->info.depth;
1290 parameters->MipLevels = This->info.mip_levels;
1291 parameters->ArraySize = This->info.array_size;
1292 parameters->DxgiFormat = This->info.format;
1293 parameters->Dimension = This->info.dimension;
1294 parameters->AlphaMode = This->info.alpha_mode;
1296 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1297 iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1298 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1300 hr = S_OK;
1302 end:
1303 LeaveCriticalSection(&This->lock);
1305 return hr;
1308 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface,
1309 UINT arrayIndex, UINT mipLevel, UINT sliceIndex,
1310 IWICBitmapFrameDecode **bitmapFrame)
1312 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1313 HRESULT hr;
1314 LARGE_INTEGER seek;
1315 UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size;
1316 UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0;
1317 UINT bytes_per_block, bytesread, i;
1318 DdsFrameDecode *frame_decode = NULL;
1320 TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame);
1322 if (!bitmapFrame) return E_INVALIDARG;
1324 EnterCriticalSection(&This->lock);
1326 if (!This->initialized) {
1327 hr = WINCODEC_ERR_WRONGSTATE;
1328 goto end;
1331 if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) ||
1332 (arrayIndex >= This->info.array_size * 6) ||
1333 (mipLevel >= This->info.mip_levels) ||
1334 (sliceIndex >= This->info.depth)) {
1335 hr = E_INVALIDARG;
1336 goto end;
1339 if (is_compressed(This->info.format)) {
1340 block_width = DDS_BLOCK_WIDTH;
1341 block_height = DDS_BLOCK_HEIGHT;
1342 } else {
1343 block_width = 1;
1344 block_height = 1;
1346 bytes_per_block = This->info.bytes_per_block;
1347 seek.QuadPart = This->info.data_offset;
1349 width = This->info.width;
1350 height = This->info.height;
1351 depth = This->info.depth;
1352 for (i = 0; i < This->info.mip_levels; i++)
1354 width_in_blocks = (width + block_width - 1) / block_width;
1355 height_in_blocks = (height + block_height - 1) / block_height;
1356 size = width_in_blocks * height_in_blocks * bytes_per_block;
1358 if (i < mipLevel) {
1359 seek.QuadPart += size * depth;
1360 } else if (i == mipLevel){
1361 seek.QuadPart += size * sliceIndex;
1362 frame_width = width;
1363 frame_height = height;
1364 frame_width_in_blocks = width_in_blocks;
1365 frame_height_in_blocks = height_in_blocks;
1366 frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block;
1367 if (arrayIndex == 0) break;
1369 seek.QuadPart += arrayIndex * size * depth;
1371 if (width > 1) width /= 2;
1372 if (height > 1) height /= 2;
1373 if (depth > 1) depth /= 2;
1376 hr = DdsFrameDecode_CreateInstance(&frame_decode);
1377 if (hr != S_OK) goto end;
1378 frame_decode->info.width = frame_width;
1379 frame_decode->info.height = frame_height;
1380 frame_decode->info.format = This->info.format;
1381 frame_decode->info.bytes_per_block = bytes_per_block;
1382 frame_decode->info.block_width = block_width;
1383 frame_decode->info.block_height = block_height;
1384 frame_decode->info.width_in_blocks = frame_width_in_blocks;
1385 frame_decode->info.height_in_blocks = frame_height_in_blocks;
1386 frame_decode->info.pixel_format = This->info.pixel_format;
1387 frame_decode->info.pixel_format_bpp = This->info.pixel_format_bpp;
1388 frame_decode->block_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
1389 frame_decode->pixel_data = NULL;
1390 hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL);
1391 if (hr != S_OK) goto end;
1392 hr = IStream_Read(This->stream, frame_decode->block_data, frame_size, &bytesread);
1393 if (hr != S_OK || bytesread != frame_size) {
1394 hr = WINCODEC_ERR_STREAMREAD;
1395 goto end;
1397 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
1399 hr = S_OK;
1401 end:
1402 LeaveCriticalSection(&This->lock);
1404 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
1406 return hr;
1409 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = {
1410 DdsDecoder_Dds_QueryInterface,
1411 DdsDecoder_Dds_AddRef,
1412 DdsDecoder_Dds_Release,
1413 DdsDecoder_Dds_GetParameters,
1414 DdsDecoder_Dds_GetFrame
1417 static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv)
1419 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1420 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1423 static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface)
1425 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1426 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1429 static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface)
1431 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1432 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1435 static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options)
1437 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1438 DDS_HEADER_DXT10 header_dxt10;
1439 LARGE_INTEGER seek;
1440 DDS_HEADER header;
1441 ULONG bytesread;
1442 DWORD magic;
1443 HRESULT hr;
1445 TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options);
1447 EnterCriticalSection(&This->lock);
1449 if (This->initialized) {
1450 hr = WINCODEC_ERR_WRONGSTATE;
1451 goto end;
1454 seek.QuadPart = 0;
1455 hr = IStream_Seek(stream, seek, SEEK_SET, NULL);
1456 if (FAILED(hr)) goto end;
1458 hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread);
1459 if (FAILED(hr)) goto end;
1460 if (bytesread != sizeof(magic)) {
1461 hr = WINCODEC_ERR_STREAMREAD;
1462 goto end;
1464 if (magic != DDS_MAGIC) {
1465 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
1466 goto end;
1469 hr = IStream_Read(stream, &header, sizeof(header), &bytesread);
1470 if (FAILED(hr)) goto end;
1471 if (bytesread != sizeof(header)) {
1472 hr = WINCODEC_ERR_STREAMREAD;
1473 goto end;
1475 if (header.size != sizeof(header)) {
1476 hr = WINCODEC_ERR_BADHEADER;
1477 goto end;
1480 if (has_extended_header(&header)) {
1481 hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread);
1482 if (FAILED(hr)) goto end;
1483 if (bytesread != sizeof(header_dxt10)) {
1484 hr = WINCODEC_ERR_STREAMREAD;
1485 goto end;
1489 get_dds_info(&This->info, &header, &header_dxt10);
1491 This->initialized = TRUE;
1492 This->stream = stream;
1493 IStream_AddRef(stream);
1495 end:
1496 LeaveCriticalSection(&This->lock);
1498 return hr;
1501 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = {
1502 DdsDecoder_Wine_QueryInterface,
1503 DdsDecoder_Wine_AddRef,
1504 DdsDecoder_Wine_Release,
1505 DdsDecoder_Wine_Initialize
1508 static HRESULT WINAPI DdsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
1510 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1511 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1513 if (!ppv) return E_INVALIDARG;
1515 if (IsEqualIID(&IID_IUnknown, iid) ||
1516 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1518 *ppv = &This->IWICBitmapFrameEncode_iface;
1520 else
1522 *ppv = NULL;
1523 return E_NOINTERFACE;
1526 IUnknown_AddRef((IUnknown*)*ppv);
1527 return S_OK;
1530 static ULONG WINAPI DdsFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1532 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1533 ULONG ref = InterlockedIncrement(&This->ref);
1535 TRACE("(%p) refcount=%u\n", iface, ref);
1537 return ref;
1540 static ULONG WINAPI DdsFrameEncode_Release(IWICBitmapFrameEncode *iface)
1542 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1543 ULONG ref = InterlockedDecrement(&This->ref);
1545 TRACE("(%p) refcount=%u\n", iface, ref);
1547 if (ref == 0)
1549 IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface);
1550 HeapFree(GetProcessHeap(), 0, This);
1553 return ref;
1556 static HRESULT WINAPI DdsFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
1557 IPropertyBag2 *encoderOptions)
1559 FIXME("(%p,%p): stub\n", iface, encoderOptions);
1560 return E_NOTIMPL;
1563 static HRESULT WINAPI DdsFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
1564 UINT width, UINT height)
1566 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1567 HRESULT hr;
1569 TRACE("(%p,%u,%u)\n", iface, width, height);
1571 EnterCriticalSection(&This->parent->lock);
1573 if (!This->initialized || This->frame_created)
1575 hr = WINCODEC_ERR_WRONGSTATE;
1577 else
1579 This->width = width;
1580 This->height = height;
1581 hr = S_OK;
1584 LeaveCriticalSection(&This->parent->lock);
1586 return hr;
1589 static HRESULT WINAPI DdsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
1590 double dpiX, double dpiY)
1592 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1593 HRESULT hr;
1595 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
1597 EnterCriticalSection(&This->parent->lock);
1599 if (!This->initialized || This->frame_created)
1601 hr = WINCODEC_ERR_WRONGSTATE;
1603 else
1605 This->dpi_x = dpiX;
1606 This->dpi_y = dpiY;
1607 hr = S_OK;
1610 LeaveCriticalSection(&This->parent->lock);
1612 return hr;
1615 static HRESULT WINAPI DdsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
1616 WICPixelFormatGUID *pixelFormat)
1618 FIXME("(%p,%s): stub\n", iface, debugstr_guid(pixelFormat));
1619 return E_NOTIMPL;
1622 static HRESULT WINAPI DdsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
1623 UINT count, IWICColorContext **colorContext)
1625 FIXME("(%p,%u,%p): stub\n", iface, count, colorContext);
1626 return E_NOTIMPL;
1629 static HRESULT WINAPI DdsFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
1630 IWICPalette *palette)
1632 FIXME("(%p,%p): stub\n", iface, palette);
1633 return E_NOTIMPL;
1636 static HRESULT WINAPI DdsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
1637 IWICBitmapSource *thumbnail)
1639 TRACE("(%p,%p)\n", iface, thumbnail);
1640 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1643 static HRESULT WINAPI DdsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
1644 UINT lineCount, UINT stride, UINT bufferSize, BYTE *pixels)
1646 FIXME("(%p,%u,%u,%u,%p): stub\n", iface, lineCount, stride, bufferSize, pixels);
1647 return E_NOTIMPL;
1650 static HRESULT WINAPI DdsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
1651 IWICBitmapSource *bitmapSource, WICRect *rc)
1653 FIXME("(%p,%p,%s): stub\n", iface, bitmapSource, debug_wic_rect(rc));
1654 return E_NOTIMPL;
1657 static HRESULT WINAPI DdsFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1659 FIXME("(%p): stub\n", iface);
1660 return E_NOTIMPL;
1663 static HRESULT WINAPI DdsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1664 IWICMetadataQueryWriter **metadataQueryWriter)
1666 FIXME("(%p,%p): stub\n", iface, metadataQueryWriter);
1667 return E_NOTIMPL;
1670 static const IWICBitmapFrameEncodeVtbl DdsFrameEncode_Vtbl = {
1671 DdsFrameEncode_QueryInterface,
1672 DdsFrameEncode_AddRef,
1673 DdsFrameEncode_Release,
1674 DdsFrameEncode_Initialize,
1675 DdsFrameEncode_SetSize,
1676 DdsFrameEncode_SetResolution,
1677 DdsFrameEncode_SetPixelFormat,
1678 DdsFrameEncode_SetColorContexts,
1679 DdsFrameEncode_SetPalette,
1680 DdsFrameEncode_SetThumbnail,
1681 DdsFrameEncode_WritePixels,
1682 DdsFrameEncode_WriteSource,
1683 DdsFrameEncode_Commit,
1684 DdsFrameEncode_GetMetadataQueryWriter
1687 HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv)
1689 DdsDecoder *This;
1690 HRESULT ret;
1692 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1694 *ppv = NULL;
1696 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder));
1697 if (!This) return E_OUTOFMEMORY;
1699 This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl;
1700 This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl;
1701 This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl;
1702 This->ref = 1;
1703 This->initialized = FALSE;
1704 This->stream = NULL;
1705 InitializeCriticalSection(&This->lock);
1706 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock");
1708 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1709 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1711 return ret;
1714 static HRESULT WINAPI DdsEncoder_Dds_QueryInterface(IWICDdsEncoder *iface, REFIID iid,
1715 void **ppv)
1717 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1718 return IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
1721 static ULONG WINAPI DdsEncoder_Dds_AddRef(IWICDdsEncoder *iface)
1723 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1724 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
1727 static ULONG WINAPI DdsEncoder_Dds_Release(IWICDdsEncoder *iface)
1729 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1730 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1733 static HRESULT WINAPI DdsEncoder_Dds_SetParameters(IWICDdsEncoder *iface,
1734 WICDdsParameters *parameters)
1736 FIXME("(%p,%p): stub.\n", iface, parameters);
1737 return E_NOTIMPL;
1740 static HRESULT WINAPI DdsEncoder_Dds_GetParameters(IWICDdsEncoder *iface,
1741 WICDdsParameters *parameters)
1743 FIXME("(%p,%p): stub.\n", iface, parameters);
1744 return E_NOTIMPL;
1747 static HRESULT WINAPI DdsEncoder_Dds_CreateNewFrame(IWICDdsEncoder *iface,
1748 IWICBitmapFrameEncode **frameEncode,
1749 UINT *arrayIndex, UINT *mipLevel, UINT *sliceIndex)
1751 FIXME("(%p,%p,%p,%p,%p): stub.\n", iface, frameEncode, arrayIndex, mipLevel, sliceIndex);
1752 return E_NOTIMPL;
1755 static const IWICDdsEncoderVtbl DdsEncoder_Dds_Vtbl =
1757 DdsEncoder_Dds_QueryInterface,
1758 DdsEncoder_Dds_AddRef,
1759 DdsEncoder_Dds_Release,
1760 DdsEncoder_Dds_SetParameters,
1761 DdsEncoder_Dds_GetParameters,
1762 DdsEncoder_Dds_CreateNewFrame
1765 static HRESULT WINAPI DdsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1766 void **ppv)
1768 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1769 FIXME("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1771 if (!ppv) return E_INVALIDARG;
1773 if (IsEqualIID(&IID_IUnknown, iid) ||
1774 IsEqualIID(&IID_IWICBitmapEncoder, iid)) {
1775 *ppv = &This->IWICBitmapEncoder_iface;
1776 } else if (IsEqualIID(&IID_IWICDdsEncoder, iid)) {
1777 *ppv = &This->IWICDdsEncoder_iface;
1778 } else {
1779 *ppv = NULL;
1780 return E_NOINTERFACE;
1783 IUnknown_AddRef((IUnknown*)*ppv);
1784 return S_OK;
1787 static ULONG WINAPI DdsEncoder_AddRef(IWICBitmapEncoder *iface)
1789 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1790 ULONG ref = InterlockedIncrement(&This->ref);
1792 TRACE("(%p) refcount=%u\n", iface, ref);
1794 return ref;
1797 static ULONG WINAPI DdsEncoder_Release(IWICBitmapEncoder *iface)
1799 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1800 ULONG ref = InterlockedDecrement(&This->ref);
1802 TRACE("(%p) refcount=%u\n", iface, ref);
1804 if (ref == 0) {
1805 This->lock.DebugInfo->Spare[0] = 0;
1806 DeleteCriticalSection(&This->lock);
1807 if (This->stream) IStream_Release(This->stream);
1808 HeapFree(GetProcessHeap(), 0, This);
1811 return ref;
1814 static HRESULT WINAPI DdsEncoder_Initialize(IWICBitmapEncoder *iface,
1815 IStream *stream, WICBitmapEncoderCacheOption cacheOption)
1817 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1818 HRESULT hr;
1820 TRACE("(%p,%p,%u)\n", iface, stream, cacheOption);
1822 if (cacheOption != WICBitmapEncoderNoCache)
1823 FIXME("Cache option %#x is not supported.\n", cacheOption);
1825 if (!stream) return E_INVALIDARG;
1827 EnterCriticalSection(&This->lock);
1829 if (This->stream)
1831 hr = WINCODEC_ERR_WRONGSTATE;
1832 goto end;
1835 This->stream = stream;
1836 IStream_AddRef(stream);
1838 hr = S_OK;
1840 end:
1841 LeaveCriticalSection(&This->lock);
1843 return hr;
1846 static HRESULT WINAPI DdsEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
1848 TRACE("(%p,%p)\n", iface, format);
1850 if (!format)
1851 return E_INVALIDARG;
1853 memcpy(format, &GUID_ContainerFormatDds, sizeof(*format));
1854 return S_OK;
1857 static HRESULT WINAPI DdsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
1859 IWICComponentInfo *comp_info;
1860 HRESULT hr;
1862 TRACE("%p,%p\n", iface, info);
1864 if (!info) return E_INVALIDARG;
1866 hr = CreateComponentInfo(&CLSID_WICDdsEncoder, &comp_info);
1867 if (hr == S_OK) {
1868 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
1869 IWICComponentInfo_Release(comp_info);
1871 return hr;
1874 static HRESULT WINAPI DdsEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1875 UINT cCount, IWICColorContext **ppIColorContext)
1877 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1878 return E_NOTIMPL;
1881 static HRESULT WINAPI DdsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
1883 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1884 HRESULT hr;
1886 TRACE("(%p,%p)\n", iface, palette);
1888 EnterCriticalSection(&This->lock);
1890 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
1892 LeaveCriticalSection(&This->lock);
1894 return hr;
1897 static HRESULT WINAPI DdsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1899 TRACE("(%p,%p)\n", iface, pIThumbnail);
1900 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1903 static HRESULT WINAPI DdsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1905 TRACE("(%p,%p)\n", iface, pIPreview);
1906 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1909 static HRESULT WINAPI DdsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1910 IWICBitmapFrameEncode **frameEncode, IPropertyBag2 **encoderOptions)
1912 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1913 DdsFrameEncode *result;
1914 HRESULT hr;
1916 TRACE("(%p,%p,%p)\n", iface, frameEncode, encoderOptions);
1918 EnterCriticalSection(&This->lock);
1920 if (!This->stream)
1922 hr = WINCODEC_ERR_WRONGSTATE;
1923 goto end;
1926 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
1927 if (!result)
1929 hr = E_OUTOFMEMORY;
1930 goto end;
1933 result->IWICBitmapFrameEncode_iface.lpVtbl = &DdsFrameEncode_Vtbl;
1934 result->ref = 1;
1935 result->parent = This;
1936 result->initialized = FALSE;
1937 result->frame_created = FALSE;
1938 IWICBitmapEncoder_AddRef(iface);
1940 *frameEncode = &result->IWICBitmapFrameEncode_iface;
1941 hr = S_OK;
1943 end:
1944 LeaveCriticalSection(&This->lock);
1945 return hr;
1948 static HRESULT WINAPI DdsEncoder_Commit(IWICBitmapEncoder *iface)
1950 FIXME("(%p): stub\n", iface);
1951 return E_NOTIMPL;
1954 static HRESULT WINAPI DdsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1955 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1957 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1958 return E_NOTIMPL;
1961 static const IWICBitmapEncoderVtbl DdsEncoder_Vtbl = {
1962 DdsEncoder_QueryInterface,
1963 DdsEncoder_AddRef,
1964 DdsEncoder_Release,
1965 DdsEncoder_Initialize,
1966 DdsEncoder_GetContainerFormat,
1967 DdsEncoder_GetEncoderInfo,
1968 DdsEncoder_SetColorContexts,
1969 DdsEncoder_SetPalette,
1970 DdsEncoder_SetThumbnail,
1971 DdsEncoder_SetPreview,
1972 DdsEncoder_CreateNewFrame,
1973 DdsEncoder_Commit,
1974 DdsEncoder_GetMetadataQueryWriter
1977 HRESULT DdsEncoder_CreateInstance( REFIID iid, void **ppv)
1979 DdsEncoder *This;
1980 HRESULT ret;
1982 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1984 *ppv = NULL;
1986 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsEncoder));
1987 if (!This) return E_OUTOFMEMORY;
1989 This->IWICBitmapEncoder_iface.lpVtbl = &DdsEncoder_Vtbl;
1990 This->IWICDdsEncoder_iface.lpVtbl = &DdsEncoder_Dds_Vtbl;
1991 This->ref = 1;
1992 This->stream = NULL;
1993 This->frame_count = 0;
1994 This->uncommitted_frame = FALSE;
1995 This->committed = FALSE;
1996 InitializeCriticalSection(&This->lock);
1997 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsEncoder.lock");
1999 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2000 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2002 return ret;