sapi: Implement ISpRegDataKey CreateKey.
[wine.git] / dlls / windowscodecs / ddsformat.c
blob62cd0dc3f7c2ab9c896a205d7af5f7f00096cce0
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 UINT frame_index;
170 BOOL uncommitted_frame;
171 BOOL committed;
172 dds_info info;
173 } DdsEncoder;
175 typedef struct DdsFrameEncode {
176 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
177 LONG ref;
178 DdsEncoder *parent;
179 BOOL initialized;
180 BOOL frame_created;
181 UINT width;
182 UINT height;
183 double dpi_x;
184 double dpi_y;
185 } DdsFrameEncode;
187 static struct dds_format {
188 DDS_PIXELFORMAT pixel_format;
189 const GUID *wic_format;
190 UINT wic_format_bpp;
191 DXGI_FORMAT dxgi_format;
192 } dds_format_table[] = {
193 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 },
194 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC1_UNORM },
195 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 },
196 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC2_UNORM },
197 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 },
198 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC2_UNORM },
199 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 },
200 &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC3_UNORM },
201 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 },
202 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC3_UNORM },
203 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 },
204 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
205 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 },
206 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_SNORM },
207 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 },
208 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
209 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 },
210 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_SNORM },
211 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 },
212 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM },
213 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 },
214 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM },
215 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 },
216 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_R8G8_B8G8_UNORM },
217 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 },
218 &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_G8R8_G8B8_UNORM },
219 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 },
220 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN },
221 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 },
222 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
223 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 },
224 &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_SNORM },
225 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 },
226 &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
227 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 },
228 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_FLOAT },
229 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 },
230 &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
231 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 },
232 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
233 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 },
234 &GUID_WICPixelFormatUndefined, 32, DXGI_FORMAT_R32G32_FLOAT },
235 { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 },
236 &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
237 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 },
238 &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
239 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0 },
240 &GUID_WICPixelFormat32bppRGB, 32, DXGI_FORMAT_UNKNOWN },
241 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 },
242 &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
243 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 },
244 &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
245 /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM.
246 * For "correct" one, the RGB masks should be 0x3FF,0xFFC00,0x3FF00000.
247 * see: https://walbourn.github.io/dds-update-and-1010102-problems */
248 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF00000,0xFFC00,0x3FF,0xC0000000 },
249 &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
250 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 },
251 &GUID_WICPixelFormat32bppRGBA1010102, 32, DXGI_FORMAT_UNKNOWN },
252 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 },
253 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_UNORM },
254 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 },
255 &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
256 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0xFF0000,0x00FF00,0x0000FF,0 },
257 &GUID_WICPixelFormat24bppBGR, 24, DXGI_FORMAT_UNKNOWN },
258 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0x0000FF,0x00FF00,0xFF0000,0 },
259 &GUID_WICPixelFormat24bppRGB, 24, DXGI_FORMAT_UNKNOWN },
260 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 },
261 &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
262 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0 },
263 &GUID_WICPixelFormat16bppBGR555, 16, DXGI_FORMAT_UNKNOWN },
264 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 },
265 &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
266 { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 },
267 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_B4G4R4A4_UNORM },
268 { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF },
269 &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
270 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 },
271 &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
272 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 },
273 &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R8G8_UNORM },
274 { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 },
275 &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
276 { { 0 }, &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM },
277 { { 0 }, &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM },
278 { { 0 }, &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM },
279 { { 0 }, &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT },
280 { { 0 }, &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM },
281 { { 0 }, &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM },
282 { { 0 }, &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT },
283 { { 0 }, &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM },
284 { { 0 }, &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM },
285 { { 0 }, &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM },
286 { { 0 }, &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM },
287 { { 0 }, &GUID_WICPixelFormat32bppRGBE, 32, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
288 { { 0 }, &GUID_WICPixelFormat32bppRGBA1010102XR, 32, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM },
289 { { 0 }, &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM },
290 { { 0 }, &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT },
291 { { 0 }, &GUID_WICPixelFormat96bppRGBFloat, 96, DXGI_FORMAT_R32G32B32_FLOAT },
292 { { 0 }, &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT },
293 { { 0 }, &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN }
296 static DXGI_FORMAT compressed_formats[] = {
297 DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB,
298 DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB,
299 DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB,
300 DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM,
301 DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM,
302 DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16,
303 DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB
306 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **);
308 static DWORD rgb565_to_argb(WORD color, BYTE alpha)
310 return MAKE_ARGB(alpha, (GET_RGB565_R(color) * 0xFF + 0x0F) / 0x1F,
311 (GET_RGB565_G(color) * 0xFF + 0x1F) / 0x3F,
312 (GET_RGB565_B(color) * 0xFF + 0x0F) / 0x1F);
315 static inline BOOL has_extended_header(DDS_HEADER *header)
317 return (header->ddspf.flags & DDPF_FOURCC) &&
318 (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0'));
321 static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
323 if (header_dxt10) {
324 if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube;
325 switch (header_dxt10->resourceDimension)
327 case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D;
328 case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D;
329 case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D;
330 default: return WICDdsTexture2D;
332 } else {
333 if (header->caps2 & DDSCAPS2_CUBEMAP) {
334 return WICDdsTextureCube;
335 } else if (header->caps2 & DDSCAPS2_VOLUME) {
336 return WICDdsTexture3D;
337 } else {
338 return WICDdsTexture2D;
343 static struct dds_format *get_dds_format(DDS_PIXELFORMAT *pixel_format)
345 UINT i;
347 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
349 if ((pixel_format->flags & dds_format_table[i].pixel_format.flags) &&
350 (pixel_format->fourCC == dds_format_table[i].pixel_format.fourCC) &&
351 (pixel_format->rgbBitCount == dds_format_table[i].pixel_format.rgbBitCount) &&
352 (pixel_format->rBitMask == dds_format_table[i].pixel_format.rBitMask) &&
353 (pixel_format->gBitMask == dds_format_table[i].pixel_format.gBitMask) &&
354 (pixel_format->bBitMask == dds_format_table[i].pixel_format.bBitMask) &&
355 (pixel_format->aBitMask == dds_format_table[i].pixel_format.aBitMask))
356 return dds_format_table + i;
359 return dds_format_table + ARRAY_SIZE(dds_format_table) - 1;
362 static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc)
364 switch (fourcc)
366 case MAKEFOURCC('D', 'X', 'T', '1'):
367 case MAKEFOURCC('D', 'X', 'T', '2'):
368 case MAKEFOURCC('D', 'X', 'T', '4'):
369 return WICDdsAlphaModePremultiplied;
370 default:
371 return WICDdsAlphaModeUnknown;
375 static UINT get_bytes_per_block_from_format(DXGI_FORMAT format)
377 /* for uncompressed format, return bytes per pixel*/
378 switch (format)
380 case DXGI_FORMAT_R8_TYPELESS:
381 case DXGI_FORMAT_R8_UNORM:
382 case DXGI_FORMAT_R8_UINT:
383 case DXGI_FORMAT_R8_SNORM:
384 case DXGI_FORMAT_R8_SINT:
385 case DXGI_FORMAT_A8_UNORM:
386 return 1;
387 case DXGI_FORMAT_R8G8_TYPELESS:
388 case DXGI_FORMAT_R8G8_UNORM:
389 case DXGI_FORMAT_R8G8_UINT:
390 case DXGI_FORMAT_R8G8_SNORM:
391 case DXGI_FORMAT_R8G8_SINT:
392 case DXGI_FORMAT_R16_TYPELESS:
393 case DXGI_FORMAT_R16_FLOAT:
394 case DXGI_FORMAT_D16_UNORM:
395 case DXGI_FORMAT_R16_UNORM:
396 case DXGI_FORMAT_R16_UINT:
397 case DXGI_FORMAT_R16_SNORM:
398 case DXGI_FORMAT_R16_SINT:
399 case DXGI_FORMAT_B5G6R5_UNORM:
400 case DXGI_FORMAT_B5G5R5A1_UNORM:
401 case DXGI_FORMAT_B4G4R4A4_UNORM:
402 return 2;
403 case DXGI_FORMAT_R10G10B10A2_TYPELESS:
404 case DXGI_FORMAT_R10G10B10A2_UNORM:
405 case DXGI_FORMAT_R10G10B10A2_UINT:
406 case DXGI_FORMAT_R11G11B10_FLOAT:
407 case DXGI_FORMAT_R8G8B8A8_TYPELESS:
408 case DXGI_FORMAT_R8G8B8A8_UNORM:
409 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
410 case DXGI_FORMAT_R8G8B8A8_UINT:
411 case DXGI_FORMAT_R8G8B8A8_SNORM:
412 case DXGI_FORMAT_R8G8B8A8_SINT:
413 case DXGI_FORMAT_R16G16_TYPELESS:
414 case DXGI_FORMAT_R16G16_FLOAT:
415 case DXGI_FORMAT_R16G16_UNORM:
416 case DXGI_FORMAT_R16G16_UINT:
417 case DXGI_FORMAT_R16G16_SNORM:
418 case DXGI_FORMAT_R16G16_SINT:
419 case DXGI_FORMAT_R32_TYPELESS:
420 case DXGI_FORMAT_D32_FLOAT:
421 case DXGI_FORMAT_R32_FLOAT:
422 case DXGI_FORMAT_R32_UINT:
423 case DXGI_FORMAT_R32_SINT:
424 case DXGI_FORMAT_R24G8_TYPELESS:
425 case DXGI_FORMAT_D24_UNORM_S8_UINT:
426 case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
427 case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
428 case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
429 case DXGI_FORMAT_R8G8_B8G8_UNORM:
430 case DXGI_FORMAT_G8R8_G8B8_UNORM:
431 case DXGI_FORMAT_B8G8R8A8_UNORM:
432 case DXGI_FORMAT_B8G8R8X8_UNORM:
433 case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
434 case DXGI_FORMAT_B8G8R8A8_TYPELESS:
435 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
436 case DXGI_FORMAT_B8G8R8X8_TYPELESS:
437 case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
438 return 4;
439 case DXGI_FORMAT_BC1_UNORM:
440 case DXGI_FORMAT_BC1_TYPELESS:
441 case DXGI_FORMAT_BC1_UNORM_SRGB:
442 case DXGI_FORMAT_BC4_TYPELESS:
443 case DXGI_FORMAT_BC4_UNORM:
444 case DXGI_FORMAT_BC4_SNORM:
445 case DXGI_FORMAT_R16G16B16A16_TYPELESS:
446 case DXGI_FORMAT_R16G16B16A16_FLOAT:
447 case DXGI_FORMAT_R16G16B16A16_UNORM:
448 case DXGI_FORMAT_R16G16B16A16_UINT:
449 case DXGI_FORMAT_R16G16B16A16_SNORM:
450 case DXGI_FORMAT_R16G16B16A16_SINT:
451 case DXGI_FORMAT_R32G32_TYPELESS:
452 case DXGI_FORMAT_R32G32_FLOAT:
453 case DXGI_FORMAT_R32G32_UINT:
454 case DXGI_FORMAT_R32G32_SINT:
455 case DXGI_FORMAT_R32G8X24_TYPELESS:
456 case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
457 case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
458 case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
459 return 8;
460 case DXGI_FORMAT_R32G32B32_TYPELESS:
461 case DXGI_FORMAT_R32G32B32_FLOAT:
462 case DXGI_FORMAT_R32G32B32_UINT:
463 case DXGI_FORMAT_R32G32B32_SINT:
464 return 12;
465 case DXGI_FORMAT_BC2_UNORM:
466 case DXGI_FORMAT_BC2_TYPELESS:
467 case DXGI_FORMAT_BC2_UNORM_SRGB:
468 case DXGI_FORMAT_BC3_UNORM:
469 case DXGI_FORMAT_BC3_TYPELESS:
470 case DXGI_FORMAT_BC3_UNORM_SRGB:
471 case DXGI_FORMAT_BC5_TYPELESS:
472 case DXGI_FORMAT_BC5_UNORM:
473 case DXGI_FORMAT_BC5_SNORM:
474 case DXGI_FORMAT_BC6H_TYPELESS:
475 case DXGI_FORMAT_BC6H_UF16:
476 case DXGI_FORMAT_BC6H_SF16:
477 case DXGI_FORMAT_BC7_TYPELESS:
478 case DXGI_FORMAT_BC7_UNORM:
479 case DXGI_FORMAT_BC7_UNORM_SRGB:
480 case DXGI_FORMAT_R32G32B32A32_TYPELESS:
481 case DXGI_FORMAT_R32G32B32A32_FLOAT:
482 case DXGI_FORMAT_R32G32B32A32_UINT:
483 case DXGI_FORMAT_R32G32B32A32_SINT:
484 return 16;
485 default:
486 WARN("DXGI format 0x%x is not supported in DDS decoder\n", format);
487 return 0;
491 static UINT get_frame_count(UINT depth, UINT mip_levels, UINT array_size, WICDdsDimension dimension)
493 UINT frame_count, i;
495 if (depth == 1)
497 frame_count = mip_levels;
499 else
501 frame_count = 0;
502 for (i = 0; i < mip_levels; i++)
504 frame_count += depth;
505 if (depth > 1) depth /= 2;
509 frame_count *= array_size;
510 if (dimension == WICDdsTextureCube) frame_count *= 6;
512 return frame_count;
515 static void get_frame_dds_index(UINT index, dds_info *info, UINT *array_index, UINT *mip_level, UINT *slice_index)
517 UINT frame_per_texture, depth;
519 if (info->dimension == WICDdsTextureCube)
520 frame_per_texture = info->mip_levels;
521 else
522 frame_per_texture = info->frame_count / info->array_size;
524 *array_index = index / frame_per_texture;
525 *slice_index = index % frame_per_texture;
526 depth = info->depth;
527 *mip_level = 0;
528 while (*slice_index >= depth)
530 *slice_index -= depth;
531 (*mip_level)++;
532 if (depth > 1) depth /= 2;
536 static const GUID *dxgi_format_to_wic_format(DXGI_FORMAT dxgi_format)
538 UINT i;
539 for (i = 0; i < ARRAY_SIZE(dds_format_table); i++)
541 if (dds_format_table[i].pixel_format.size == 0 &&
542 dds_format_table[i].dxgi_format == dxgi_format)
543 return dds_format_table[i].wic_format;
545 return &GUID_WICPixelFormatUndefined;
548 static BOOL is_compressed(DXGI_FORMAT format)
550 UINT i;
552 for (i = 0; i < ARRAY_SIZE(compressed_formats); i++)
554 if (format == compressed_formats[i]) return TRUE;
556 return FALSE;
559 static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10)
561 struct dds_format *format_info;
563 info->width = header->width;
564 info->height = header->height;
565 info->depth = 1;
566 info->mip_levels = 1;
567 info->array_size = 1;
568 if (header->depth) info->depth = header->depth;
569 if (header->mipMapCount) info->mip_levels = header->mipMapCount;
571 if (has_extended_header(header)) {
572 if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize;
573 info->format = header_dxt10->dxgiFormat;
574 info->dimension = get_dimension(NULL, header_dxt10);
575 info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008;
576 info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10);
577 if (is_compressed(info->format)) {
578 info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ?
579 &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA;
580 info->pixel_format_bpp = 32;
581 } else {
582 info->pixel_format = dxgi_format_to_wic_format(info->format);
583 info->pixel_format_bpp = get_bytes_per_block_from_format(info->format) * 8;
585 } else {
586 format_info = get_dds_format(&header->ddspf);
587 info->format = format_info->dxgi_format;
588 info->dimension = get_dimension(header, NULL);
589 info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC);
590 info->data_offset = sizeof(DWORD) + sizeof(*header);
591 info->pixel_format = format_info->wic_format;
592 info->pixel_format_bpp = format_info->wic_format_bpp;
595 if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) {
596 info->bytes_per_block = header->ddspf.rgbBitCount / 8;
597 } else {
598 info->bytes_per_block = get_bytes_per_block_from_format(info->format);
601 info->frame_count = get_frame_count(info->depth, info->mip_levels, info->array_size, info->dimension);
604 static void decode_block(const BYTE *block_data, UINT block_count, DXGI_FORMAT format,
605 UINT width, UINT height, DWORD *buffer)
607 const BYTE *block, *color_indices, *alpha_indices, *alpha_table;
608 int i, j, x, y, block_x, block_y, color_index, alpha_index;
609 int block_size, color_offset, color_indices_offset;
610 WORD color[4], color_value = 0;
611 BYTE alpha[8], alpha_value = 0;
613 if (format == DXGI_FORMAT_BC1_UNORM) {
614 block_size = 8;
615 color_offset = 0;
616 color_indices_offset = 4;
617 } else {
618 block_size = 16;
619 color_offset = 8;
620 color_indices_offset = 12;
622 block_x = 0;
623 block_y = 0;
625 for (i = 0; i < block_count; i++)
627 block = block_data + i * block_size;
629 color[0] = *((WORD *)(block + color_offset));
630 color[1] = *((WORD *)(block + color_offset + 2));
631 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) * 2 + GET_RGB565_R(color[1]) + 1) / 3),
632 ((GET_RGB565_G(color[0]) * 2 + GET_RGB565_G(color[1]) + 1) / 3),
633 ((GET_RGB565_B(color[0]) * 2 + GET_RGB565_B(color[1]) + 1) / 3));
634 color[3] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) * 2 + 1) / 3),
635 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) * 2 + 1) / 3),
636 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) * 2 + 1) / 3));
638 switch (format)
640 case DXGI_FORMAT_BC1_UNORM:
641 if (color[0] <= color[1]) {
642 color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) + 1) / 2),
643 ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) + 1) / 2),
644 ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) + 1) / 2));
645 color[3] = 0;
647 break;
648 case DXGI_FORMAT_BC2_UNORM:
649 alpha_table = block;
650 break;
651 case DXGI_FORMAT_BC3_UNORM:
652 alpha[0] = *block;
653 alpha[1] = *(block + 1);
654 if (alpha[0] > alpha[1]) {
655 for (j = 2; j < 8; j++)
657 alpha[j] = (BYTE)((alpha[0] * (8 - j) + alpha[1] * (j - 1) + 3) / 7);
659 } else {
660 for (j = 2; j < 6; j++)
662 alpha[j] = (BYTE)((alpha[0] * (6 - j) + alpha[1] * (j - 1) + 2) / 5);
664 alpha[6] = 0;
665 alpha[7] = 0xFF;
667 alpha_indices = block + 2;
668 break;
669 default:
670 break;
673 color_indices = block + color_indices_offset;
674 for (j = 0; j < 16; j++)
676 x = block_x + j % 4;
677 y = block_y + j / 4;
678 if (x >= width || y >= height) continue;
680 color_index = (color_indices[j / 4] >> ((j % 4) * 2)) & 0x3;
681 color_value = color[color_index];
683 switch (format)
685 case DXGI_FORMAT_BC1_UNORM:
686 if ((color[0] <= color[1]) && !color_value) {
687 color_value = 0;
688 alpha_value = 0;
689 } else {
690 alpha_value = 0xFF;
692 break;
693 case DXGI_FORMAT_BC2_UNORM:
694 alpha_value = (alpha_table[j / 2] >> (j % 2) * 4) & 0xF;
695 alpha_value = (BYTE)((alpha_value * 0xFF + 0x7)/ 0xF);
696 break;
697 case DXGI_FORMAT_BC3_UNORM:
698 alpha_index = (*((DWORD *)(alpha_indices + (j / 8) * 3)) >> ((j % 8) * 3)) & 0x7;
699 alpha_value = alpha[alpha_index];
700 break;
701 default:
702 break;
704 buffer[x + y * width] = rgb565_to_argb(color_value, alpha_value);
707 block_x += DDS_BLOCK_WIDTH;
708 if (block_x >= width) {
709 block_x = 0;
710 block_y += DDS_BLOCK_HEIGHT;
715 static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
717 return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface);
720 static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface)
722 return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface);
725 static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface)
727 return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface);
730 static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
732 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface);
735 static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface)
737 return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface);
740 static inline DdsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
742 return CONTAINING_RECORD(iface, DdsEncoder, IWICBitmapEncoder_iface);
745 static inline DdsEncoder *impl_from_IWICDdsEncoder(IWICDdsEncoder *iface)
747 return CONTAINING_RECORD(iface, DdsEncoder, IWICDdsEncoder_iface);
750 static inline DdsFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
752 return CONTAINING_RECORD(iface, DdsFrameEncode, IWICBitmapFrameEncode_iface);
755 static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
756 void **ppv)
758 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
759 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
761 if (!ppv) return E_INVALIDARG;
763 if (IsEqualIID(&IID_IUnknown, iid) ||
764 IsEqualIID(&IID_IWICBitmapSource, iid) ||
765 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) {
766 *ppv = &This->IWICBitmapFrameDecode_iface;
767 } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) {
768 *ppv = &This->IWICDdsFrameDecode_iface;
769 } else {
770 *ppv = NULL;
771 return E_NOINTERFACE;
774 IUnknown_AddRef((IUnknown*)*ppv);
775 return S_OK;
778 static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
780 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
781 ULONG ref = InterlockedIncrement(&This->ref);
783 TRACE("(%p) refcount=%lu\n", iface, ref);
785 return ref;
788 static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface)
790 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
791 ULONG ref = InterlockedDecrement(&This->ref);
793 TRACE("(%p) refcount=%lu\n", iface, ref);
795 if (ref == 0) {
796 if (This->pixel_data != This->block_data) HeapFree(GetProcessHeap(), 0, This->pixel_data);
797 HeapFree(GetProcessHeap(), 0, This->block_data);
798 HeapFree(GetProcessHeap(), 0, This);
801 return ref;
804 static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
805 UINT *puiWidth, UINT *puiHeight)
807 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
809 if (!puiWidth || !puiHeight) return E_INVALIDARG;
811 *puiWidth = This->info.width;
812 *puiHeight = This->info.height;
814 TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight);
816 return S_OK;
819 static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
820 WICPixelFormatGUID *pPixelFormat)
822 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
824 if (!pPixelFormat) return E_INVALIDARG;
826 *pPixelFormat = *This->info.pixel_format;
828 TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat));
830 return S_OK;
833 static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
834 double *pDpiX, double *pDpiY)
836 FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY);
838 return E_NOTIMPL;
841 static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
842 IWICPalette *pIPalette)
844 FIXME("(%p,%p): stub.\n", iface, pIPalette);
846 return E_NOTIMPL;
849 static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
850 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
852 DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
853 UINT bpp, frame_stride, frame_size;
854 INT x, y, width, height;
855 HRESULT hr;
857 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
859 if (!pbBuffer) return E_INVALIDARG;
861 bpp = This->info.pixel_format_bpp;
862 if (!bpp) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
864 frame_stride = This->info.width * bpp / 8;
865 frame_size = frame_stride * This->info.height;
866 if (!prc) {
867 if (cbStride < frame_stride) return E_INVALIDARG;
868 if (cbBufferSize < frame_size) return WINCODEC_ERR_INSUFFICIENTBUFFER;
869 } else {
870 x = prc->X;
871 y = prc->Y;
872 width = prc->Width;
873 height = prc->Height;
874 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
875 x + width > This->info.width ||
876 y + height > This->info.height) {
877 return E_INVALIDARG;
879 if (cbStride < width * bpp / 8) return E_INVALIDARG;
880 if (cbBufferSize < cbStride * height) return WINCODEC_ERR_INSUFFICIENTBUFFER;
883 EnterCriticalSection(&This->lock);
885 if (!This->pixel_data) {
886 if (is_compressed(This->info.format)) {
887 This->pixel_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
888 if (!This->pixel_data) {
889 hr = E_OUTOFMEMORY;
890 goto end;
892 decode_block(This->block_data, This->info.width_in_blocks * This->info.height_in_blocks, This->info.format,
893 This->info.width, This->info.height, (DWORD *)This->pixel_data);
894 } else {
895 This->pixel_data = This->block_data;
899 hr = copy_pixels(bpp, This->pixel_data, This->info.width, This->info.height, frame_stride,
900 prc, cbStride, cbBufferSize, pbBuffer);
902 end:
903 LeaveCriticalSection(&This->lock);
905 return hr;
908 static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
909 IWICMetadataQueryReader **ppIMetadataQueryReader)
911 FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader);
913 return E_NOTIMPL;
916 static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
917 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
919 FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount);
921 return E_NOTIMPL;
924 static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
925 IWICBitmapSource **ppIThumbnail)
927 FIXME("(%p,%p): stub.\n", iface, ppIThumbnail);
929 return E_NOTIMPL;
932 static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = {
933 DdsFrameDecode_QueryInterface,
934 DdsFrameDecode_AddRef,
935 DdsFrameDecode_Release,
936 DdsFrameDecode_GetSize,
937 DdsFrameDecode_GetPixelFormat,
938 DdsFrameDecode_GetResolution,
939 DdsFrameDecode_CopyPalette,
940 DdsFrameDecode_CopyPixels,
941 DdsFrameDecode_GetMetadataQueryReader,
942 DdsFrameDecode_GetColorContexts,
943 DdsFrameDecode_GetThumbnail
946 static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface,
947 REFIID iid, void **ppv)
949 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
950 return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
953 static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface)
955 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
956 return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
959 static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface)
961 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
962 return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
965 static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface,
966 UINT *widthInBlocks, UINT *heightInBlocks)
968 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
970 if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG;
972 *widthInBlocks = This->info.width_in_blocks;
973 *heightInBlocks = This->info.height_in_blocks;
975 TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks);
977 return S_OK;
980 static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface,
981 WICDdsFormatInfo *formatInfo)
983 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
985 if (!formatInfo) return E_INVALIDARG;
987 formatInfo->DxgiFormat = This->info.format;
988 formatInfo->BytesPerBlock = This->info.bytes_per_block;
989 formatInfo->BlockWidth = This->info.block_width;
990 formatInfo->BlockHeight = This->info.block_height;
992 TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo,
993 formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight);
995 return S_OK;
998 static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface,
999 const WICRect *boundsInBlocks, UINT stride, UINT bufferSize,
1000 BYTE *buffer)
1002 DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface);
1003 int x, y, width, height;
1004 UINT bytes_per_block, frame_stride, frame_size;
1006 TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer);
1008 if (!buffer) return E_INVALIDARG;
1010 bytes_per_block = This->info.bytes_per_block;
1011 frame_stride = This->info.width_in_blocks * bytes_per_block;
1012 frame_size = frame_stride * This->info.height_in_blocks;
1014 if (!boundsInBlocks) {
1015 if (stride < frame_stride) return E_INVALIDARG;
1016 if (bufferSize < frame_size) return E_INVALIDARG;
1017 } else {
1018 x = boundsInBlocks->X;
1019 y = boundsInBlocks->Y;
1020 width = boundsInBlocks->Width;
1021 height = boundsInBlocks->Height;
1022 if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
1023 x + width > This->info.width_in_blocks ||
1024 y + height > This->info.height_in_blocks) {
1025 return E_INVALIDARG;
1027 if (stride < width * bytes_per_block) return E_INVALIDARG;
1028 if (bufferSize < stride * height) return E_INVALIDARG;
1031 return copy_pixels(This->info.bytes_per_block * 8, This->block_data, This->info.width_in_blocks,
1032 This->info.height_in_blocks, frame_stride, boundsInBlocks, stride, bufferSize, buffer);
1035 static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = {
1036 DdsFrameDecode_Dds_QueryInterface,
1037 DdsFrameDecode_Dds_AddRef,
1038 DdsFrameDecode_Dds_Release,
1039 DdsFrameDecode_Dds_GetSizeInBlocks,
1040 DdsFrameDecode_Dds_GetFormatInfo,
1041 DdsFrameDecode_Dds_CopyBlocks
1044 static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode)
1046 DdsFrameDecode *result;
1048 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
1049 if (!result) return E_OUTOFMEMORY;
1051 result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl;
1052 result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl;
1053 result->ref = 1;
1054 InitializeCriticalSection(&result->lock);
1055 result->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsFrameDecode.lock");
1057 *frame_decode = result;
1058 return S_OK;
1061 static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1062 void **ppv)
1064 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1065 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1067 if (!ppv) return E_INVALIDARG;
1069 if (IsEqualIID(&IID_IUnknown, iid) ||
1070 IsEqualIID(&IID_IWICBitmapDecoder, iid)) {
1071 *ppv = &This->IWICBitmapDecoder_iface;
1072 } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) {
1073 *ppv = &This->IWICDdsDecoder_iface;
1074 } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) {
1075 *ppv = &This->IWICWineDecoder_iface;
1076 } else {
1077 *ppv = NULL;
1078 return E_NOINTERFACE;
1081 IUnknown_AddRef((IUnknown*)*ppv);
1082 return S_OK;
1085 static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface)
1087 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1088 ULONG ref = InterlockedIncrement(&This->ref);
1090 TRACE("(%p) refcount=%lu\n", iface, ref);
1092 return ref;
1095 static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface)
1097 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1098 ULONG ref = InterlockedDecrement(&This->ref);
1100 TRACE("(%p) refcount=%lu\n", iface, ref);
1102 if (ref == 0)
1104 This->lock.DebugInfo->Spare[0] = 0;
1105 DeleteCriticalSection(&This->lock);
1106 if (This->stream) IStream_Release(This->stream);
1107 HeapFree(GetProcessHeap(), 0, This);
1110 return ref;
1113 static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1114 DWORD *capability)
1116 FIXME("(%p,%p,%p): stub.\n", iface, stream, capability);
1118 return E_NOTIMPL;
1121 static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1122 WICDecodeOptions cacheOptions)
1124 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1125 HRESULT hr;
1127 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1129 EnterCriticalSection(&This->lock);
1131 hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions);
1132 if (FAILED(hr)) goto end;
1134 if (This->info.dimension == WICDdsTextureCube ||
1135 (This->info.format != DXGI_FORMAT_BC1_UNORM &&
1136 This->info.format != DXGI_FORMAT_BC2_UNORM &&
1137 This->info.format != DXGI_FORMAT_BC3_UNORM)) {
1138 IStream_Release(pIStream);
1139 This->stream = NULL;
1140 This->initialized = FALSE;
1141 hr = WINCODEC_ERR_BADHEADER;
1144 end:
1145 LeaveCriticalSection(&This->lock);
1147 return hr;
1150 static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1151 GUID *pguidContainerFormat)
1153 TRACE("(%p,%p)\n", iface, pguidContainerFormat);
1155 memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID));
1157 return S_OK;
1160 static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1161 IWICBitmapDecoderInfo **ppIDecoderInfo)
1163 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1165 return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo);
1168 static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface,
1169 IWICPalette *pIPalette)
1171 TRACE("(%p,%p)\n", iface, pIPalette);
1173 return WINCODEC_ERR_PALETTEUNAVAILABLE;
1176 static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1177 IWICMetadataQueryReader **ppIMetadataQueryReader)
1179 if (!ppIMetadataQueryReader) return E_INVALIDARG;
1181 FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader);
1183 return E_NOTIMPL;
1186 static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface,
1187 IWICBitmapSource **ppIBitmapSource)
1189 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1191 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1194 static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1195 UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount)
1197 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount);
1199 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1202 static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1203 IWICBitmapSource **ppIThumbnail)
1205 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1207 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1210 static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1211 UINT *pCount)
1213 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1215 if (!pCount) return E_INVALIDARG;
1216 if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
1218 EnterCriticalSection(&This->lock);
1220 *pCount = This->info.frame_count;
1222 LeaveCriticalSection(&This->lock);
1224 TRACE("(%p) -> %d\n", iface, *pCount);
1226 return S_OK;
1229 static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface,
1230 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1232 DdsDecoder *This = impl_from_IWICBitmapDecoder(iface);
1233 UINT array_index, mip_level, slice_index;
1235 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1237 if (!ppIBitmapFrame) return E_INVALIDARG;
1239 EnterCriticalSection(&This->lock);
1241 if (!This->initialized) {
1242 LeaveCriticalSection(&This->lock);
1243 return WINCODEC_ERR_WRONGSTATE;
1246 get_frame_dds_index(index, &This->info, &array_index, &mip_level, &slice_index);
1248 LeaveCriticalSection(&This->lock);
1250 return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame);
1253 static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = {
1254 DdsDecoder_QueryInterface,
1255 DdsDecoder_AddRef,
1256 DdsDecoder_Release,
1257 DdsDecoder_QueryCapability,
1258 DdsDecoder_Initialize,
1259 DdsDecoder_GetContainerFormat,
1260 DdsDecoder_GetDecoderInfo,
1261 DdsDecoder_CopyPalette,
1262 DdsDecoder_GetMetadataQueryReader,
1263 DdsDecoder_GetPreview,
1264 DdsDecoder_GetColorContexts,
1265 DdsDecoder_GetThumbnail,
1266 DdsDecoder_GetFrameCount,
1267 DdsDecoder_GetFrame
1270 static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface,
1271 REFIID iid, void **ppv)
1273 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1274 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1277 static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface)
1279 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1280 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1283 static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface)
1285 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1286 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1289 static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface,
1290 WICDdsParameters *parameters)
1292 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1293 HRESULT hr;
1295 if (!parameters) return E_INVALIDARG;
1297 EnterCriticalSection(&This->lock);
1299 if (!This->initialized) {
1300 hr = WINCODEC_ERR_WRONGSTATE;
1301 goto end;
1304 parameters->Width = This->info.width;
1305 parameters->Height = This->info.height;
1306 parameters->Depth = This->info.depth;
1307 parameters->MipLevels = This->info.mip_levels;
1308 parameters->ArraySize = This->info.array_size;
1309 parameters->DxgiFormat = This->info.format;
1310 parameters->Dimension = This->info.dimension;
1311 parameters->AlphaMode = This->info.alpha_mode;
1313 TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n",
1314 iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1315 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1317 hr = S_OK;
1319 end:
1320 LeaveCriticalSection(&This->lock);
1322 return hr;
1325 static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface,
1326 UINT arrayIndex, UINT mipLevel, UINT sliceIndex,
1327 IWICBitmapFrameDecode **bitmapFrame)
1329 DdsDecoder *This = impl_from_IWICDdsDecoder(iface);
1330 HRESULT hr;
1331 LARGE_INTEGER seek;
1332 UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size;
1333 UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0;
1334 UINT bytes_per_block, i;
1335 DWORD bytesread;
1336 DdsFrameDecode *frame_decode = NULL;
1338 TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame);
1340 if (!bitmapFrame) return E_INVALIDARG;
1342 EnterCriticalSection(&This->lock);
1344 if (!This->initialized) {
1345 hr = WINCODEC_ERR_WRONGSTATE;
1346 goto end;
1349 if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) ||
1350 (arrayIndex >= This->info.array_size * 6) ||
1351 (mipLevel >= This->info.mip_levels) ||
1352 (sliceIndex >= This->info.depth)) {
1353 hr = E_INVALIDARG;
1354 goto end;
1357 if (is_compressed(This->info.format)) {
1358 block_width = DDS_BLOCK_WIDTH;
1359 block_height = DDS_BLOCK_HEIGHT;
1360 } else {
1361 block_width = 1;
1362 block_height = 1;
1364 bytes_per_block = This->info.bytes_per_block;
1365 seek.QuadPart = This->info.data_offset;
1367 width = This->info.width;
1368 height = This->info.height;
1369 depth = This->info.depth;
1370 for (i = 0; i < This->info.mip_levels; i++)
1372 width_in_blocks = (width + block_width - 1) / block_width;
1373 height_in_blocks = (height + block_height - 1) / block_height;
1374 size = width_in_blocks * height_in_blocks * bytes_per_block;
1376 if (i < mipLevel) {
1377 seek.QuadPart += size * depth;
1378 } else if (i == mipLevel){
1379 seek.QuadPart += size * sliceIndex;
1380 frame_width = width;
1381 frame_height = height;
1382 frame_width_in_blocks = width_in_blocks;
1383 frame_height_in_blocks = height_in_blocks;
1384 frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block;
1385 if (arrayIndex == 0) break;
1387 seek.QuadPart += arrayIndex * size * depth;
1389 if (width > 1) width /= 2;
1390 if (height > 1) height /= 2;
1391 if (depth > 1) depth /= 2;
1394 hr = DdsFrameDecode_CreateInstance(&frame_decode);
1395 if (hr != S_OK) goto end;
1396 frame_decode->info.width = frame_width;
1397 frame_decode->info.height = frame_height;
1398 frame_decode->info.format = This->info.format;
1399 frame_decode->info.bytes_per_block = bytes_per_block;
1400 frame_decode->info.block_width = block_width;
1401 frame_decode->info.block_height = block_height;
1402 frame_decode->info.width_in_blocks = frame_width_in_blocks;
1403 frame_decode->info.height_in_blocks = frame_height_in_blocks;
1404 frame_decode->info.pixel_format = This->info.pixel_format;
1405 frame_decode->info.pixel_format_bpp = This->info.pixel_format_bpp;
1406 frame_decode->block_data = HeapAlloc(GetProcessHeap(), 0, frame_size);
1407 frame_decode->pixel_data = NULL;
1408 hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL);
1409 if (hr != S_OK) goto end;
1410 hr = IStream_Read(This->stream, frame_decode->block_data, frame_size, &bytesread);
1411 if (hr != S_OK || bytesread != frame_size) {
1412 hr = WINCODEC_ERR_STREAMREAD;
1413 goto end;
1415 *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface;
1417 hr = S_OK;
1419 end:
1420 LeaveCriticalSection(&This->lock);
1422 if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface);
1424 return hr;
1427 static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = {
1428 DdsDecoder_Dds_QueryInterface,
1429 DdsDecoder_Dds_AddRef,
1430 DdsDecoder_Dds_Release,
1431 DdsDecoder_Dds_GetParameters,
1432 DdsDecoder_Dds_GetFrame
1435 static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv)
1437 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1438 return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1441 static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface)
1443 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1444 return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1447 static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface)
1449 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1450 return DdsDecoder_Release(&This->IWICBitmapDecoder_iface);
1453 static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options)
1455 DdsDecoder *This = impl_from_IWICWineDecoder(iface);
1456 DDS_HEADER_DXT10 header_dxt10;
1457 LARGE_INTEGER seek;
1458 DDS_HEADER header;
1459 ULONG bytesread;
1460 DWORD magic;
1461 HRESULT hr;
1463 TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options);
1465 EnterCriticalSection(&This->lock);
1467 if (This->initialized) {
1468 hr = WINCODEC_ERR_WRONGSTATE;
1469 goto end;
1472 seek.QuadPart = 0;
1473 hr = IStream_Seek(stream, seek, SEEK_SET, NULL);
1474 if (FAILED(hr)) goto end;
1476 hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread);
1477 if (FAILED(hr)) goto end;
1478 if (bytesread != sizeof(magic)) {
1479 hr = WINCODEC_ERR_STREAMREAD;
1480 goto end;
1482 if (magic != DDS_MAGIC) {
1483 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
1484 goto end;
1487 hr = IStream_Read(stream, &header, sizeof(header), &bytesread);
1488 if (FAILED(hr)) goto end;
1489 if (bytesread != sizeof(header)) {
1490 hr = WINCODEC_ERR_STREAMREAD;
1491 goto end;
1493 if (header.size != sizeof(header)) {
1494 hr = WINCODEC_ERR_BADHEADER;
1495 goto end;
1498 if (has_extended_header(&header)) {
1499 hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread);
1500 if (FAILED(hr)) goto end;
1501 if (bytesread != sizeof(header_dxt10)) {
1502 hr = WINCODEC_ERR_STREAMREAD;
1503 goto end;
1507 get_dds_info(&This->info, &header, &header_dxt10);
1509 This->initialized = TRUE;
1510 This->stream = stream;
1511 IStream_AddRef(stream);
1513 end:
1514 LeaveCriticalSection(&This->lock);
1516 return hr;
1519 static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = {
1520 DdsDecoder_Wine_QueryInterface,
1521 DdsDecoder_Wine_AddRef,
1522 DdsDecoder_Wine_Release,
1523 DdsDecoder_Wine_Initialize
1526 static HRESULT WINAPI DdsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
1528 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1529 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1531 if (!ppv) return E_INVALIDARG;
1533 if (IsEqualIID(&IID_IUnknown, iid) ||
1534 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1536 *ppv = &This->IWICBitmapFrameEncode_iface;
1538 else
1540 *ppv = NULL;
1541 return E_NOINTERFACE;
1544 IUnknown_AddRef((IUnknown*)*ppv);
1545 return S_OK;
1548 static ULONG WINAPI DdsFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1550 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1551 ULONG ref = InterlockedIncrement(&This->ref);
1553 TRACE("(%p) refcount=%lu\n", iface, ref);
1555 return ref;
1558 static ULONG WINAPI DdsFrameEncode_Release(IWICBitmapFrameEncode *iface)
1560 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1561 ULONG ref = InterlockedDecrement(&This->ref);
1563 TRACE("(%p) refcount=%lu\n", iface, ref);
1565 if (ref == 0)
1567 IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface);
1568 HeapFree(GetProcessHeap(), 0, This);
1571 return ref;
1574 static HRESULT WINAPI DdsFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
1575 IPropertyBag2 *encoderOptions)
1577 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1578 HRESULT hr;
1580 TRACE("(%p,%p)\n", iface, encoderOptions);
1581 if (encoderOptions) FIXME("encoder options are not supported for DDS.\n");
1583 EnterCriticalSection(&This->parent->lock);
1585 if (This->initialized)
1587 hr = WINCODEC_ERR_WRONGSTATE;
1589 else
1591 This->initialized = TRUE;
1592 hr = S_OK;
1595 LeaveCriticalSection(&This->parent->lock);
1597 return hr;
1600 static HRESULT WINAPI DdsFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
1601 UINT width, UINT height)
1603 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1604 HRESULT hr;
1606 TRACE("(%p,%u,%u)\n", iface, width, height);
1608 EnterCriticalSection(&This->parent->lock);
1610 if (!This->initialized || This->frame_created)
1612 hr = WINCODEC_ERR_WRONGSTATE;
1614 else
1616 This->width = width;
1617 This->height = height;
1618 hr = S_OK;
1621 LeaveCriticalSection(&This->parent->lock);
1623 return hr;
1626 static HRESULT WINAPI DdsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
1627 double dpiX, double dpiY)
1629 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1630 HRESULT hr;
1632 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
1634 EnterCriticalSection(&This->parent->lock);
1636 if (!This->initialized || This->frame_created)
1638 hr = WINCODEC_ERR_WRONGSTATE;
1640 else
1642 This->dpi_x = dpiX;
1643 This->dpi_y = dpiY;
1644 hr = S_OK;
1647 LeaveCriticalSection(&This->parent->lock);
1649 return hr;
1652 static HRESULT WINAPI DdsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
1653 WICPixelFormatGUID *pixelFormat)
1655 DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1656 HRESULT hr;
1658 TRACE("(%p,%s)\n", iface, debugstr_guid(pixelFormat));
1660 EnterCriticalSection(&This->parent->lock);
1662 if (!This->initialized)
1664 hr = WINCODEC_ERR_NOTINITIALIZED;
1666 else if (This->frame_created)
1668 hr = WINCODEC_ERR_WRONGSTATE;
1670 else
1672 *pixelFormat = GUID_WICPixelFormat32bppBGRA;
1673 hr = S_OK;
1676 LeaveCriticalSection(&This->parent->lock);
1678 return hr;
1681 static HRESULT WINAPI DdsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
1682 UINT count, IWICColorContext **colorContext)
1684 FIXME("(%p,%u,%p): stub\n", iface, count, colorContext);
1685 return E_NOTIMPL;
1688 static HRESULT WINAPI DdsFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
1689 IWICPalette *palette)
1691 FIXME("(%p,%p): stub\n", iface, palette);
1692 return E_NOTIMPL;
1695 static HRESULT WINAPI DdsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
1696 IWICBitmapSource *thumbnail)
1698 TRACE("(%p,%p)\n", iface, thumbnail);
1699 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1702 static HRESULT WINAPI DdsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
1703 UINT lineCount, UINT stride, UINT bufferSize, BYTE *pixels)
1705 FIXME("(%p,%u,%u,%u,%p): stub\n", iface, lineCount, stride, bufferSize, pixels);
1706 return E_NOTIMPL;
1709 static HRESULT WINAPI DdsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
1710 IWICBitmapSource *bitmapSource, WICRect *rc)
1712 FIXME("(%p,%p,%s): stub\n", iface, bitmapSource, debug_wic_rect(rc));
1713 return E_NOTIMPL;
1716 static HRESULT WINAPI DdsFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1718 FIXME("(%p): stub\n", iface);
1719 return E_NOTIMPL;
1722 static HRESULT WINAPI DdsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1723 IWICMetadataQueryWriter **metadataQueryWriter)
1725 FIXME("(%p,%p): stub\n", iface, metadataQueryWriter);
1726 return E_NOTIMPL;
1729 static const IWICBitmapFrameEncodeVtbl DdsFrameEncode_Vtbl = {
1730 DdsFrameEncode_QueryInterface,
1731 DdsFrameEncode_AddRef,
1732 DdsFrameEncode_Release,
1733 DdsFrameEncode_Initialize,
1734 DdsFrameEncode_SetSize,
1735 DdsFrameEncode_SetResolution,
1736 DdsFrameEncode_SetPixelFormat,
1737 DdsFrameEncode_SetColorContexts,
1738 DdsFrameEncode_SetPalette,
1739 DdsFrameEncode_SetThumbnail,
1740 DdsFrameEncode_WritePixels,
1741 DdsFrameEncode_WriteSource,
1742 DdsFrameEncode_Commit,
1743 DdsFrameEncode_GetMetadataQueryWriter
1746 HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv)
1748 DdsDecoder *This;
1749 HRESULT ret;
1751 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1753 *ppv = NULL;
1755 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsDecoder));
1756 if (!This) return E_OUTOFMEMORY;
1758 This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl;
1759 This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl;
1760 This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl;
1761 This->ref = 1;
1762 This->initialized = FALSE;
1763 This->stream = NULL;
1764 InitializeCriticalSection(&This->lock);
1765 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock");
1767 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1768 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1770 return ret;
1773 static HRESULT WINAPI DdsEncoder_Dds_QueryInterface(IWICDdsEncoder *iface, REFIID iid,
1774 void **ppv)
1776 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1777 return IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
1780 static ULONG WINAPI DdsEncoder_Dds_AddRef(IWICDdsEncoder *iface)
1782 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1783 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
1786 static ULONG WINAPI DdsEncoder_Dds_Release(IWICDdsEncoder *iface)
1788 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1789 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1792 static HRESULT WINAPI DdsEncoder_Dds_SetParameters(IWICDdsEncoder *iface,
1793 WICDdsParameters *parameters)
1795 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1796 HRESULT hr;
1798 TRACE("(%p,%p)\n", iface, parameters);
1800 if (!parameters) return E_INVALIDARG;
1802 EnterCriticalSection(&This->lock);
1804 if (!This->stream)
1806 hr = WINCODEC_ERR_WRONGSTATE;
1807 goto end;
1810 This->info.width = parameters->Width;
1811 This->info.height = parameters->Height;
1812 This->info.depth = parameters->Depth;
1813 This->info.mip_levels = parameters->MipLevels;
1814 This->info.array_size = parameters->ArraySize;
1815 This->info.format = parameters->DxgiFormat;
1816 This->info.dimension = parameters->Dimension;
1817 This->info.alpha_mode = parameters->AlphaMode;
1819 This->info.bytes_per_block = get_bytes_per_block_from_format(This->info.format);
1820 This->info.frame_count = get_frame_count(This->info.depth, This->info.mip_levels,
1821 This->info.array_size, This->info.dimension);
1823 hr = S_OK;
1825 end:
1826 LeaveCriticalSection(&This->lock);
1827 return hr;
1830 static HRESULT WINAPI DdsEncoder_Dds_GetParameters(IWICDdsEncoder *iface,
1831 WICDdsParameters *parameters)
1833 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1834 HRESULT hr;
1836 TRACE("(%p,%p)\n", iface, parameters);
1838 if (!parameters) return E_INVALIDARG;
1840 EnterCriticalSection(&This->lock);
1842 if (!This->stream)
1844 hr = WINCODEC_ERR_WRONGSTATE;
1845 goto end;
1848 parameters->Width = This->info.width;
1849 parameters->Height = This->info.height;
1850 parameters->Depth = This->info.depth;
1851 parameters->MipLevels = This->info.mip_levels;
1852 parameters->ArraySize = This->info.array_size;
1853 parameters->DxgiFormat = This->info.format;
1854 parameters->Dimension = This->info.dimension;
1855 parameters->AlphaMode = This->info.alpha_mode;
1857 TRACE("(%p,%p) -> (%dx%d depth=%u mipLevels=%u arraySize=%u dxgiFormat=%#x dimension=%#x alphaMode=%#x)\n",
1858 iface, parameters, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels,
1859 parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode);
1861 hr = S_OK;
1863 end:
1864 LeaveCriticalSection(&This->lock);
1865 return hr;
1868 static HRESULT WINAPI DdsEncoder_Dds_CreateNewFrame(IWICDdsEncoder *iface,
1869 IWICBitmapFrameEncode **frameEncode,
1870 UINT *arrayIndex, UINT *mipLevel, UINT *sliceIndex)
1872 DdsEncoder *This = impl_from_IWICDdsEncoder(iface);
1873 UINT array_index, mip_level, slice_index;
1874 DdsFrameEncode *result;
1875 HRESULT hr;
1877 TRACE("(%p,%p,%p,%p,%p)\n", iface, frameEncode, arrayIndex, mipLevel, sliceIndex);
1879 EnterCriticalSection(&This->lock);
1881 if (!This->stream || This->committed || This->uncommitted_frame)
1883 hr = WINCODEC_ERR_WRONGSTATE;
1884 goto end;
1887 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
1888 if (!result)
1890 hr = E_OUTOFMEMORY;
1891 goto end;
1894 get_frame_dds_index(This->frame_index, &This->info, &array_index, &mip_level, &slice_index);
1895 if (arrayIndex) *arrayIndex = array_index;
1896 if (mipLevel) *mipLevel = mip_level;
1897 if (sliceIndex) *sliceIndex = slice_index;
1899 This->frame_index++;
1900 result->IWICBitmapFrameEncode_iface.lpVtbl = &DdsFrameEncode_Vtbl;
1901 result->ref = 1;
1902 result->parent = This;
1903 result->parent->uncommitted_frame = TRUE;
1904 result->initialized = FALSE;
1905 result->frame_created = FALSE;
1906 IWICDdsEncoder_AddRef(iface);
1908 *frameEncode = &result->IWICBitmapFrameEncode_iface;
1909 hr = S_OK;
1911 end:
1912 LeaveCriticalSection(&This->lock);
1913 return hr;
1916 static const IWICDdsEncoderVtbl DdsEncoder_Dds_Vtbl =
1918 DdsEncoder_Dds_QueryInterface,
1919 DdsEncoder_Dds_AddRef,
1920 DdsEncoder_Dds_Release,
1921 DdsEncoder_Dds_SetParameters,
1922 DdsEncoder_Dds_GetParameters,
1923 DdsEncoder_Dds_CreateNewFrame
1926 static HRESULT WINAPI DdsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1927 void **ppv)
1929 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1930 FIXME("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1932 if (!ppv) return E_INVALIDARG;
1934 if (IsEqualIID(&IID_IUnknown, iid) ||
1935 IsEqualIID(&IID_IWICBitmapEncoder, iid)) {
1936 *ppv = &This->IWICBitmapEncoder_iface;
1937 } else if (IsEqualIID(&IID_IWICDdsEncoder, iid)) {
1938 *ppv = &This->IWICDdsEncoder_iface;
1939 } else {
1940 *ppv = NULL;
1941 return E_NOINTERFACE;
1944 IUnknown_AddRef((IUnknown*)*ppv);
1945 return S_OK;
1948 static ULONG WINAPI DdsEncoder_AddRef(IWICBitmapEncoder *iface)
1950 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1951 ULONG ref = InterlockedIncrement(&This->ref);
1953 TRACE("(%p) refcount=%lu\n", iface, ref);
1955 return ref;
1958 static ULONG WINAPI DdsEncoder_Release(IWICBitmapEncoder *iface)
1960 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1961 ULONG ref = InterlockedDecrement(&This->ref);
1963 TRACE("(%p) refcount=%lu\n", iface, ref);
1965 if (ref == 0) {
1966 This->lock.DebugInfo->Spare[0] = 0;
1967 DeleteCriticalSection(&This->lock);
1968 if (This->stream) IStream_Release(This->stream);
1969 HeapFree(GetProcessHeap(), 0, This);
1972 return ref;
1975 static HRESULT WINAPI DdsEncoder_Initialize(IWICBitmapEncoder *iface,
1976 IStream *stream, WICBitmapEncoderCacheOption cacheOption)
1978 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
1979 HRESULT hr;
1981 TRACE("(%p,%p,%u)\n", iface, stream, cacheOption);
1983 if (cacheOption != WICBitmapEncoderNoCache)
1984 FIXME("Cache option %#x is not supported.\n", cacheOption);
1986 if (!stream) return E_INVALIDARG;
1988 EnterCriticalSection(&This->lock);
1990 if (This->stream)
1992 hr = WINCODEC_ERR_WRONGSTATE;
1993 goto end;
1996 This->stream = stream;
1997 IStream_AddRef(stream);
1999 This->info.width = 1;
2000 This->info.height = 1;
2001 This->info.depth = 1;
2002 This->info.mip_levels = 1;
2003 This->info.array_size = 1;
2004 This->info.frame_count = 1;
2005 This->info.data_offset = 0;
2006 This->info.bytes_per_block = get_bytes_per_block_from_format(DXGI_FORMAT_BC3_UNORM);
2007 This->info.format = DXGI_FORMAT_BC3_UNORM;
2008 This->info.dimension = WICDdsTexture2D;
2009 This->info.alpha_mode = WICDdsAlphaModeUnknown;
2010 This->info.pixel_format = &GUID_WICPixelFormatUndefined;
2011 This->info.pixel_format_bpp = 0;
2013 hr = S_OK;
2015 end:
2016 LeaveCriticalSection(&This->lock);
2018 return hr;
2021 static HRESULT WINAPI DdsEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
2023 TRACE("(%p,%p)\n", iface, format);
2025 if (!format)
2026 return E_INVALIDARG;
2028 memcpy(format, &GUID_ContainerFormatDds, sizeof(*format));
2029 return S_OK;
2032 static HRESULT WINAPI DdsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
2034 IWICComponentInfo *comp_info;
2035 HRESULT hr;
2037 TRACE("%p,%p\n", iface, info);
2039 if (!info) return E_INVALIDARG;
2041 hr = CreateComponentInfo(&CLSID_WICDdsEncoder, &comp_info);
2042 if (hr == S_OK) {
2043 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
2044 IWICComponentInfo_Release(comp_info);
2046 return hr;
2049 static HRESULT WINAPI DdsEncoder_SetColorContexts(IWICBitmapEncoder *iface,
2050 UINT cCount, IWICColorContext **ppIColorContext)
2052 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
2053 return E_NOTIMPL;
2056 static HRESULT WINAPI DdsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2058 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
2059 HRESULT hr;
2061 TRACE("(%p,%p)\n", iface, palette);
2063 EnterCriticalSection(&This->lock);
2065 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
2067 LeaveCriticalSection(&This->lock);
2069 return hr;
2072 static HRESULT WINAPI DdsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
2074 TRACE("(%p,%p)\n", iface, pIThumbnail);
2075 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2078 static HRESULT WINAPI DdsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
2080 TRACE("(%p,%p)\n", iface, pIPreview);
2081 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2084 static HRESULT WINAPI DdsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
2085 IWICBitmapFrameEncode **frameEncode, IPropertyBag2 **encoderOptions)
2087 DdsEncoder *This = impl_from_IWICBitmapEncoder(iface);
2089 TRACE("(%p,%p,%p)\n", iface, frameEncode, encoderOptions);
2091 return IWICDdsEncoder_CreateNewFrame(&This->IWICDdsEncoder_iface, frameEncode, NULL, NULL, NULL);
2094 static HRESULT WINAPI DdsEncoder_Commit(IWICBitmapEncoder *iface)
2096 FIXME("(%p): stub\n", iface);
2097 return E_NOTIMPL;
2100 static HRESULT WINAPI DdsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
2101 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
2103 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
2104 return E_NOTIMPL;
2107 static const IWICBitmapEncoderVtbl DdsEncoder_Vtbl = {
2108 DdsEncoder_QueryInterface,
2109 DdsEncoder_AddRef,
2110 DdsEncoder_Release,
2111 DdsEncoder_Initialize,
2112 DdsEncoder_GetContainerFormat,
2113 DdsEncoder_GetEncoderInfo,
2114 DdsEncoder_SetColorContexts,
2115 DdsEncoder_SetPalette,
2116 DdsEncoder_SetThumbnail,
2117 DdsEncoder_SetPreview,
2118 DdsEncoder_CreateNewFrame,
2119 DdsEncoder_Commit,
2120 DdsEncoder_GetMetadataQueryWriter
2123 HRESULT DdsEncoder_CreateInstance( REFIID iid, void **ppv)
2125 DdsEncoder *This;
2126 HRESULT ret;
2128 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
2130 *ppv = NULL;
2132 This = HeapAlloc(GetProcessHeap(), 0, sizeof(DdsEncoder));
2133 if (!This) return E_OUTOFMEMORY;
2135 This->IWICBitmapEncoder_iface.lpVtbl = &DdsEncoder_Vtbl;
2136 This->IWICDdsEncoder_iface.lpVtbl = &DdsEncoder_Dds_Vtbl;
2137 This->ref = 1;
2138 This->stream = NULL;
2139 This->frame_count = 0;
2140 This->frame_index = 0;
2141 This->uncommitted_frame = FALSE;
2142 This->committed = FALSE;
2143 InitializeCriticalSection(&This->lock);
2144 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsEncoder.lock");
2146 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2147 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2149 return ret;