Sync with trunk.
[reactos.git] / dll / directx / wine / d3dx9_36 / surface.c
1 /*
2 * Copyright (C) 2009-2010 Tony Wasserka
3 * Copyright (C) 2012 Józef Kucia
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 *
19 */
20
21 #include "d3dx9_36_private.h"
22
23 #include <ole2.h>
24
25 #include <initguid.h>
26 #include <wincodec.h>
27
28 /* Wine-specific WIC GUIDs */
29 DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22);
30
31 static const struct
32 {
33 const GUID *wic_guid;
34 D3DFORMAT d3dformat;
35 } wic_pixel_formats[] = {
36 { &GUID_WICPixelFormat8bppIndexed, D3DFMT_P8 },
37 { &GUID_WICPixelFormat1bppIndexed, D3DFMT_P8 },
38 { &GUID_WICPixelFormat4bppIndexed, D3DFMT_P8 },
39 { &GUID_WICPixelFormat16bppBGR555, D3DFMT_X1R5G5B5 },
40 { &GUID_WICPixelFormat16bppBGR565, D3DFMT_R5G6B5 },
41 { &GUID_WICPixelFormat24bppBGR, D3DFMT_R8G8B8 },
42 { &GUID_WICPixelFormat32bppBGR, D3DFMT_X8R8G8B8 },
43 { &GUID_WICPixelFormat32bppBGRA, D3DFMT_A8R8G8B8 }
44 };
45
46 static D3DFORMAT wic_guid_to_d3dformat(const GUID *guid)
47 {
48 unsigned int i;
49
50 for (i = 0; i < sizeof(wic_pixel_formats) / sizeof(wic_pixel_formats[0]); i++)
51 {
52 if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid))
53 return wic_pixel_formats[i].d3dformat;
54 }
55
56 return D3DFMT_UNKNOWN;
57 }
58
59 static const GUID *d3dformat_to_wic_guid(D3DFORMAT format)
60 {
61 unsigned int i;
62
63 for (i = 0; i < sizeof(wic_pixel_formats) / sizeof(wic_pixel_formats[0]); i++)
64 {
65 if (wic_pixel_formats[i].d3dformat == format)
66 return wic_pixel_formats[i].wic_guid;
67 }
68
69 return NULL;
70 }
71
72 /* dds_header.flags */
73 #define DDS_CAPS 0x1
74 #define DDS_HEIGHT 0x2
75 #define DDS_WIDTH 0x2
76 #define DDS_PITCH 0x8
77 #define DDS_PIXELFORMAT 0x1000
78 #define DDS_MIPMAPCOUNT 0x20000
79 #define DDS_LINEARSIZE 0x80000
80 #define DDS_DEPTH 0x800000
81
82 /* dds_header.caps */
83 #define DDS_CAPS_COMPLEX 0x8
84 #define DDS_CAPS_TEXTURE 0x1000
85 #define DDS_CAPS_MIPMAP 0x400000
86
87 /* dds_header.caps2 */
88 #define DDS_CAPS2_CUBEMAP 0x200
89 #define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400
90 #define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800
91 #define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000
92 #define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000
93 #define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000
94 #define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000
95 #define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \
96 | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \
97 | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ )
98 #define DDS_CAPS2_VOLUME 0x200000
99
100 /* dds_pixel_format.flags */
101 #define DDS_PF_ALPHA 0x1
102 #define DDS_PF_ALPHA_ONLY 0x2
103 #define DDS_PF_FOURCC 0x4
104 #define DDS_PF_RGB 0x40
105 #define DDS_PF_YUV 0x200
106 #define DDS_PF_LUMINANCE 0x20000
107 #define DDS_PF_BUMPDUDV 0x80000
108
109 struct dds_pixel_format
110 {
111 DWORD size;
112 DWORD flags;
113 DWORD fourcc;
114 DWORD bpp;
115 DWORD rmask;
116 DWORD gmask;
117 DWORD bmask;
118 DWORD amask;
119 };
120
121 struct dds_header
122 {
123 DWORD signature;
124 DWORD size;
125 DWORD flags;
126 DWORD height;
127 DWORD width;
128 DWORD pitch_or_linear_size;
129 DWORD depth;
130 DWORD miplevels;
131 DWORD reserved[11];
132 struct dds_pixel_format pixel_format;
133 DWORD caps;
134 DWORD caps2;
135 DWORD caps3;
136 DWORD caps4;
137 DWORD reserved2;
138 };
139
140 static D3DFORMAT dds_fourcc_to_d3dformat(DWORD fourcc)
141 {
142 unsigned int i;
143 static const DWORD known_fourcc[] = {
144 MAKEFOURCC('U','Y','V','Y'),
145 MAKEFOURCC('Y','U','Y','2'),
146 MAKEFOURCC('R','G','B','G'),
147 MAKEFOURCC('G','R','G','B'),
148 MAKEFOURCC('D','X','T','1'),
149 MAKEFOURCC('D','X','T','2'),
150 MAKEFOURCC('D','X','T','3'),
151 MAKEFOURCC('D','X','T','4'),
152 MAKEFOURCC('D','X','T','5'),
153 D3DFMT_R16F,
154 D3DFMT_G16R16F,
155 D3DFMT_A16B16G16R16F,
156 D3DFMT_R32F,
157 D3DFMT_G32R32F,
158 D3DFMT_A32B32G32R32F,
159 };
160
161 for (i = 0; i < sizeof(known_fourcc) / sizeof(known_fourcc[0]); i++)
162 {
163 if (known_fourcc[i] == fourcc)
164 return fourcc;
165 }
166
167 WARN("Unknown FourCC %#x\n", fourcc);
168 return D3DFMT_UNKNOWN;
169 }
170
171 static const struct {
172 DWORD bpp;
173 DWORD rmask;
174 DWORD gmask;
175 DWORD bmask;
176 DWORD amask;
177 D3DFORMAT format;
178 } rgb_pixel_formats[] = {
179 { 8, 0xe0, 0x1c, 0x03, 0, D3DFMT_R3G3B2 },
180 { 16, 0xf800, 0x07e0, 0x001f, 0x0000, D3DFMT_R5G6B5 },
181 { 16, 0x7c00, 0x03e0, 0x001f, 0x8000, D3DFMT_A1R5G5B5 },
182 { 16, 0x7c00, 0x03e0, 0x001f, 0x0000, D3DFMT_X1R5G5B5 },
183 { 16, 0x0f00, 0x00f0, 0x000f, 0xf000, D3DFMT_A4R4G4B4 },
184 { 16, 0x0f00, 0x00f0, 0x000f, 0x0000, D3DFMT_X4R4G4B4 },
185 { 16, 0x00e0, 0x001c, 0x0003, 0xff00, D3DFMT_A8R3G3B2 },
186 { 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, D3DFMT_R8G8B8 },
187 { 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, D3DFMT_A8R8G8B8 },
188 { 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, D3DFMT_X8R8G8B8 },
189 { 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, D3DFMT_A2B10G10R10 },
190 { 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, D3DFMT_A2R10G10B10 },
191 { 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000, D3DFMT_G16R16 },
192 { 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, D3DFMT_A8B8G8R8 },
193 { 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, D3DFMT_X8B8G8R8 },
194 };
195
196 static D3DFORMAT dds_rgb_to_d3dformat(const struct dds_pixel_format *pixel_format)
197 {
198 unsigned int i;
199
200 for (i = 0; i < sizeof(rgb_pixel_formats) / sizeof(rgb_pixel_formats[0]); i++)
201 {
202 if (rgb_pixel_formats[i].bpp == pixel_format->bpp
203 && rgb_pixel_formats[i].rmask == pixel_format->rmask
204 && rgb_pixel_formats[i].gmask == pixel_format->gmask
205 && rgb_pixel_formats[i].bmask == pixel_format->bmask)
206 {
207 if ((pixel_format->flags & DDS_PF_ALPHA) && rgb_pixel_formats[i].amask == pixel_format->amask)
208 return rgb_pixel_formats[i].format;
209 if (rgb_pixel_formats[i].amask == 0)
210 return rgb_pixel_formats[i].format;
211 }
212 }
213
214 WARN("Unknown RGB pixel format (%#x, %#x, %#x, %#x)\n",
215 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask);
216 return D3DFMT_UNKNOWN;
217 }
218
219 static D3DFORMAT dds_luminance_to_d3dformat(const struct dds_pixel_format *pixel_format)
220 {
221 if (pixel_format->bpp == 8)
222 {
223 if (pixel_format->rmask == 0xff)
224 return D3DFMT_L8;
225 if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x0f && pixel_format->amask == 0xf0)
226 return D3DFMT_A4L4;
227 }
228 if (pixel_format->bpp == 16)
229 {
230 if (pixel_format->rmask == 0xffff)
231 return D3DFMT_L16;
232 if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x00ff && pixel_format->amask == 0xff00)
233 return D3DFMT_A8L8;
234 }
235
236 WARN("Unknown luminance pixel format (bpp %u, l %#x, a %#x)\n",
237 pixel_format->bpp, pixel_format->rmask, pixel_format->amask);
238 return D3DFMT_UNKNOWN;
239 }
240
241 static D3DFORMAT dds_alpha_to_d3dformat(const struct dds_pixel_format *pixel_format)
242 {
243 if (pixel_format->bpp == 8 && pixel_format->amask == 0xff)
244 return D3DFMT_A8;
245
246 WARN("Unknown Alpha pixel format (%u, %#x)\n", pixel_format->bpp, pixel_format->rmask);
247 return D3DFMT_UNKNOWN;
248 }
249
250 static D3DFORMAT dds_bump_to_d3dformat(const struct dds_pixel_format *pixel_format)
251 {
252 if (pixel_format->bpp == 16 && pixel_format->rmask == 0x00ff && pixel_format->gmask == 0xff00)
253 return D3DFMT_V8U8;
254 if (pixel_format->bpp == 32 && pixel_format->rmask == 0x0000ffff && pixel_format->gmask == 0xffff0000)
255 return D3DFMT_V16U16;
256
257 WARN("Unknown bump pixel format (%u, %#x, %#x, %#x, %#x)\n", pixel_format->bpp,
258 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask);
259 return D3DFMT_UNKNOWN;
260 }
261
262 static D3DFORMAT dds_pixel_format_to_d3dformat(const struct dds_pixel_format *pixel_format)
263 {
264 TRACE("pixel_format: size %u, flags %#x, fourcc %#x, bpp %u.\n", pixel_format->size,
265 pixel_format->flags, pixel_format->fourcc, pixel_format->bpp);
266 TRACE("rmask %#x, gmask %#x, bmask %#x, amask %#x.\n", pixel_format->rmask, pixel_format->gmask,
267 pixel_format->bmask, pixel_format->amask);
268
269 if (pixel_format->flags & DDS_PF_FOURCC)
270 return dds_fourcc_to_d3dformat(pixel_format->fourcc);
271 if (pixel_format->flags & DDS_PF_RGB)
272 return dds_rgb_to_d3dformat(pixel_format);
273 if (pixel_format->flags & DDS_PF_LUMINANCE)
274 return dds_luminance_to_d3dformat(pixel_format);
275 if (pixel_format->flags & DDS_PF_ALPHA_ONLY)
276 return dds_alpha_to_d3dformat(pixel_format);
277 if (pixel_format->flags & DDS_PF_BUMPDUDV)
278 return dds_bump_to_d3dformat(pixel_format);
279
280 WARN("Unknown pixel format (flags %#x, fourcc %#x, bpp %u, r %#x, g %#x, b %#x, a %#x)\n",
281 pixel_format->flags, pixel_format->fourcc, pixel_format->bpp,
282 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask);
283 return D3DFMT_UNKNOWN;
284 }
285
286 static HRESULT d3dformat_to_dds_pixel_format(struct dds_pixel_format *pixel_format, D3DFORMAT d3dformat)
287 {
288 unsigned int i;
289
290 memset(pixel_format, 0, sizeof(*pixel_format));
291
292 pixel_format->size = sizeof(*pixel_format);
293
294 for (i = 0; i < sizeof(rgb_pixel_formats) / sizeof(rgb_pixel_formats[0]); i++)
295 {
296 if (rgb_pixel_formats[i].format == d3dformat)
297 {
298 pixel_format->flags |= DDS_PF_RGB;
299 pixel_format->bpp = rgb_pixel_formats[i].bpp;
300 pixel_format->rmask = rgb_pixel_formats[i].rmask;
301 pixel_format->gmask = rgb_pixel_formats[i].gmask;
302 pixel_format->bmask = rgb_pixel_formats[i].bmask;
303 pixel_format->amask = rgb_pixel_formats[i].amask;
304 if (pixel_format->amask) pixel_format->flags |= DDS_PF_ALPHA;
305 return D3D_OK;
306 }
307 }
308
309 WARN("Unknown pixel format %#x\n", d3dformat);
310 return E_NOTIMPL;
311 }
312
313 static HRESULT calculate_dds_surface_size(D3DFORMAT format, UINT width, UINT height,
314 UINT *pitch, UINT *size)
315 {
316 const struct pixel_format_desc *format_desc = get_format_info(format);
317 if (format_desc->type == FORMAT_UNKNOWN)
318 return E_NOTIMPL;
319
320 if (format_desc->block_width != 1 || format_desc->block_height != 1)
321 {
322 *pitch = format_desc->block_byte_count
323 * max(1, (width + format_desc->block_width - 1) / format_desc->block_width);
324 *size = *pitch
325 * max(1, (height + format_desc->block_height - 1) / format_desc->block_height);
326 }
327 else
328 {
329 *pitch = width * format_desc->bytes_per_pixel;
330 *size = *pitch * height;
331 }
332
333 return D3D_OK;
334 }
335
336 static UINT calculate_dds_file_size(D3DFORMAT format, UINT width, UINT height, UINT depth,
337 UINT miplevels, UINT faces)
338 {
339 UINT i, file_size = 0;
340
341 for (i = 0; i < miplevels; i++)
342 {
343 UINT pitch, size = 0;
344 calculate_dds_surface_size(format, width, height, &pitch, &size);
345 size *= depth;
346 file_size += size;
347 width = max(1, width / 2);
348 height = max(1, height / 2);
349 depth = max(1, depth / 2);
350 }
351
352 file_size *= faces;
353 file_size += sizeof(struct dds_header);
354 return file_size;
355 }
356
357 /************************************************************
358 * get_image_info_from_dds
359 *
360 * Fills a D3DXIMAGE_INFO structure with information
361 * about a DDS file stored in the memory.
362 *
363 * PARAMS
364 * buffer [I] pointer to DDS data
365 * length [I] size of DDS data
366 * info [O] pointer to D3DXIMAGE_INFO structure
367 *
368 * RETURNS
369 * Success: D3D_OK
370 * Failure: D3DXERR_INVALIDDATA
371 *
372 */
373 static HRESULT get_image_info_from_dds(const void *buffer, UINT length, D3DXIMAGE_INFO *info)
374 {
375 UINT faces = 1;
376 UINT expected_length;
377 const struct dds_header *header = buffer;
378
379 if (length < sizeof(*header) || !info)
380 return D3DXERR_INVALIDDATA;
381
382 if (header->pixel_format.size != sizeof(header->pixel_format))
383 return D3DXERR_INVALIDDATA;
384
385 info->Width = header->width;
386 info->Height = header->height;
387 info->Depth = 1;
388 info->MipLevels = (header->flags & DDS_MIPMAPCOUNT) ? header->miplevels : 1;
389
390 info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format);
391 if (info->Format == D3DFMT_UNKNOWN)
392 return D3DXERR_INVALIDDATA;
393
394 TRACE("Pixel format is %#x\n", info->Format);
395
396 if (header->caps2 & DDS_CAPS2_VOLUME)
397 {
398 info->Depth = header->depth;
399 info->ResourceType = D3DRTYPE_VOLUMETEXTURE;
400 }
401 else if (header->caps2 & DDS_CAPS2_CUBEMAP)
402 {
403 DWORD face;
404 faces = 0;
405 for (face = DDS_CAPS2_CUBEMAP_POSITIVEX; face <= DDS_CAPS2_CUBEMAP_NEGATIVEZ; face <<= 1)
406 {
407 if (header->caps2 & face)
408 faces++;
409 }
410 info->ResourceType = D3DRTYPE_CUBETEXTURE;
411 }
412 else
413 {
414 info->ResourceType = D3DRTYPE_TEXTURE;
415 }
416
417 expected_length = calculate_dds_file_size(info->Format, info->Width, info->Height, info->Depth,
418 info->MipLevels, faces);
419 if (length < expected_length)
420 {
421 WARN("File is too short %u, expected at least %u bytes\n", length, expected_length);
422 return D3DXERR_INVALIDDATA;
423 }
424
425 info->ImageFileFormat = D3DXIFF_DDS;
426 return D3D_OK;
427 }
428
429 static HRESULT load_surface_from_dds(IDirect3DSurface9 *dst_surface, const PALETTEENTRY *dst_palette,
430 const RECT *dst_rect, const void *src_data, const RECT *src_rect, DWORD filter, D3DCOLOR color_key,
431 const D3DXIMAGE_INFO *src_info)
432 {
433 UINT size;
434 UINT src_pitch;
435 const struct dds_header *header = src_data;
436 const BYTE *pixels = (BYTE *)(header + 1);
437
438 if (src_info->ResourceType != D3DRTYPE_TEXTURE)
439 return D3DXERR_INVALIDDATA;
440
441 if (FAILED(calculate_dds_surface_size(src_info->Format, src_info->Width, src_info->Height, &src_pitch, &size)))
442 return E_NOTIMPL;
443
444 return D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect, pixels, src_info->Format,
445 src_pitch, NULL, src_rect, filter, color_key);
446 }
447
448 static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSurface9 *src_surface, const RECT *src_rect)
449 {
450 HRESULT hr;
451 UINT dst_pitch, surface_size, file_size;
452 D3DSURFACE_DESC src_desc;
453 D3DLOCKED_RECT locked_rect;
454 ID3DXBuffer *buffer;
455 struct dds_header *header;
456 BYTE *pixels;
457 struct volume volume;
458 const struct pixel_format_desc *pixel_format;
459
460 if (src_rect)
461 {
462 FIXME("Saving a part of a surface to a DDS file is not implemented yet\n");
463 return E_NOTIMPL;
464 }
465
466 hr = IDirect3DSurface9_GetDesc(src_surface, &src_desc);
467 if (FAILED(hr)) return hr;
468
469 pixel_format = get_format_info(src_desc.Format);
470 if (pixel_format->type == FORMAT_UNKNOWN) return E_NOTIMPL;
471
472 file_size = calculate_dds_file_size(src_desc.Format, src_desc.Width, src_desc.Height, 1, 1, 1);
473
474 hr = calculate_dds_surface_size(src_desc.Format, src_desc.Width, src_desc.Height, &dst_pitch, &surface_size);
475 if (FAILED(hr)) return hr;
476
477 hr = D3DXCreateBuffer(file_size, &buffer);
478 if (FAILED(hr)) return hr;
479
480 header = ID3DXBuffer_GetBufferPointer(buffer);
481 pixels = (BYTE *)(header + 1);
482
483 memset(header, 0, sizeof(*header));
484 header->signature = MAKEFOURCC('D','D','S',' ');
485 header->size = sizeof(*header);
486 header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PITCH | DDS_PIXELFORMAT | DDS_MIPMAPCOUNT;
487 header->height = src_desc.Height;
488 header->width = src_desc.Width;
489 header->pitch_or_linear_size = dst_pitch;
490 header->depth = 1;
491 header->miplevels = 1;
492 header->caps = DDS_CAPS_TEXTURE;
493 hr = d3dformat_to_dds_pixel_format(&header->pixel_format, src_desc.Format);
494 if (FAILED(hr))
495 {
496 ID3DXBuffer_Release(buffer);
497 return hr;
498 }
499
500 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, NULL, D3DLOCK_READONLY);
501 if (FAILED(hr))
502 {
503 ID3DXBuffer_Release(buffer);
504 return hr;
505 }
506
507 volume.width = src_desc.Width;
508 volume.height = src_desc.Height;
509 volume.depth = 1;
510 copy_pixels(locked_rect.pBits, locked_rect.Pitch, 0, pixels, dst_pitch, 0,
511 &volume, pixel_format);
512
513 IDirect3DSurface9_UnlockRect(src_surface);
514
515 *dst_buffer = buffer;
516 return D3D_OK;
517 }
518
519 HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette,
520 const D3DBOX *dst_box, const void *src_data, const D3DBOX *src_box, DWORD filter, D3DCOLOR color_key,
521 const D3DXIMAGE_INFO *src_info)
522 {
523 UINT row_pitch, slice_pitch;
524 const struct dds_header *header = src_data;
525 const BYTE *pixels = (BYTE *)(header + 1);
526
527 if (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE)
528 return D3DXERR_INVALIDDATA;
529
530 if (FAILED(calculate_dds_surface_size(src_info->Format, src_info->Width, src_info->Height, &row_pitch, &slice_pitch)))
531 return E_NOTIMPL;
532
533 return D3DXLoadVolumeFromMemory(dst_volume, dst_palette, dst_box, pixels, src_info->Format,
534 row_pitch, slice_pitch, NULL, src_box, filter, color_key);
535 }
536
537 HRESULT load_texture_from_dds(IDirect3DTexture9 *texture, const void *src_data, const PALETTEENTRY *palette,
538 DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info, unsigned int skip_levels,
539 unsigned int *loaded_miplevels)
540 {
541 HRESULT hr;
542 RECT src_rect;
543 UINT src_pitch;
544 UINT mip_level;
545 UINT mip_levels;
546 UINT mip_level_size;
547 UINT width, height;
548 IDirect3DSurface9 *surface;
549 const struct dds_header *header = src_data;
550 const BYTE *pixels = (BYTE *)(header + 1);
551
552 /* Loading a cube texture as a simple texture is also supported
553 * (only first face texture is taken). Same with volume textures. */
554 if ((src_info->ResourceType != D3DRTYPE_TEXTURE)
555 && (src_info->ResourceType != D3DRTYPE_CUBETEXTURE)
556 && (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE))
557 {
558 WARN("Trying to load a %u resource as a 2D texture, returning failure.\n", src_info->ResourceType);
559 return D3DXERR_INVALIDDATA;
560 }
561
562 width = src_info->Width;
563 height = src_info->Height;
564 mip_levels = min(src_info->MipLevels, IDirect3DTexture9_GetLevelCount(texture));
565 if (src_info->ResourceType == D3DRTYPE_VOLUMETEXTURE)
566 mip_levels = 1;
567 for (mip_level = 0; mip_level < mip_levels + skip_levels; ++mip_level)
568 {
569 hr = calculate_dds_surface_size(src_info->Format, width, height, &src_pitch, &mip_level_size);
570 if (FAILED(hr)) return hr;
571
572 if (mip_level >= skip_levels)
573 {
574 SetRect(&src_rect, 0, 0, width, height);
575
576 IDirect3DTexture9_GetSurfaceLevel(texture, mip_level - skip_levels, &surface);
577 hr = D3DXLoadSurfaceFromMemory(surface, palette, NULL, pixels, src_info->Format, src_pitch,
578 NULL, &src_rect, filter, color_key);
579 IDirect3DSurface9_Release(surface);
580 if (FAILED(hr))
581 return hr;
582 }
583
584 pixels += mip_level_size;
585 width = max(1, width / 2);
586 height = max(1, height / 2);
587 }
588
589 *loaded_miplevels = mip_levels - skip_levels;
590
591 return D3D_OK;
592 }
593
594 HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data,
595 const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info)
596 {
597 HRESULT hr;
598 int face;
599 UINT mip_level;
600 UINT size;
601 RECT src_rect;
602 UINT src_pitch;
603 UINT mip_levels;
604 UINT mip_level_size;
605 IDirect3DSurface9 *surface;
606 const struct dds_header *header = src_data;
607 const BYTE *pixels = (BYTE *)(header + 1);
608
609 if (src_info->ResourceType != D3DRTYPE_CUBETEXTURE)
610 return D3DXERR_INVALIDDATA;
611
612 if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES)
613 {
614 WARN("Only full cubemaps are supported\n");
615 return D3DXERR_INVALIDDATA;
616 }
617
618 mip_levels = min(src_info->MipLevels, IDirect3DCubeTexture9_GetLevelCount(cube_texture));
619 for (face = D3DCUBEMAP_FACE_POSITIVE_X; face <= D3DCUBEMAP_FACE_NEGATIVE_Z; face++)
620 {
621 size = src_info->Width;
622 for (mip_level = 0; mip_level < src_info->MipLevels; mip_level++)
623 {
624 hr = calculate_dds_surface_size(src_info->Format, size, size, &src_pitch, &mip_level_size);
625 if (FAILED(hr)) return hr;
626
627 /* if texture has fewer mip levels than DDS file, skip excessive mip levels */
628 if (mip_level < mip_levels)
629 {
630 SetRect(&src_rect, 0, 0, size, size);
631
632 IDirect3DCubeTexture9_GetCubeMapSurface(cube_texture, face, mip_level, &surface);
633 hr = D3DXLoadSurfaceFromMemory(surface, palette, NULL, pixels, src_info->Format, src_pitch,
634 NULL, &src_rect, filter, color_key);
635 IDirect3DSurface9_Release(surface);
636 if (FAILED(hr)) return hr;
637 }
638
639 pixels += mip_level_size;
640 size = max(1, size / 2);
641 }
642 }
643
644 return D3D_OK;
645 }
646
647 HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, const void *src_data,
648 const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info)
649 {
650 HRESULT hr;
651 UINT mip_level;
652 UINT mip_levels;
653 UINT src_slice_pitch;
654 UINT src_row_pitch;
655 D3DBOX src_box;
656 UINT width, height, depth;
657 IDirect3DVolume9 *volume;
658 const struct dds_header *header = src_data;
659 const BYTE *pixels = (BYTE *)(header + 1);
660
661 if (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE)
662 return D3DXERR_INVALIDDATA;
663
664 width = src_info->Width;
665 height = src_info->Height;
666 depth = src_info->Depth;
667 mip_levels = min(src_info->MipLevels, IDirect3DVolumeTexture9_GetLevelCount(volume_texture));
668
669 for (mip_level = 0; mip_level < mip_levels; mip_level++)
670 {
671 hr = calculate_dds_surface_size(src_info->Format, width, height, &src_row_pitch, &src_slice_pitch);
672 if (FAILED(hr)) return hr;
673
674 hr = IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, mip_level, &volume);
675 if (FAILED(hr)) return hr;
676
677 src_box.Left = 0;
678 src_box.Top = 0;
679 src_box.Right = width;
680 src_box.Bottom = height;
681 src_box.Front = 0;
682 src_box.Back = depth;
683
684 hr = D3DXLoadVolumeFromMemory(volume, palette, NULL, pixels, src_info->Format,
685 src_row_pitch, src_slice_pitch, NULL, &src_box, filter, color_key);
686
687 IDirect3DVolume9_Release(volume);
688 if (FAILED(hr)) return hr;
689
690 pixels += depth * src_slice_pitch;
691 width = max(1, width / 2);
692 height = max(1, height / 2);
693 depth = max(1, depth / 2);
694 }
695
696 return D3D_OK;
697 }
698
699 static BOOL convert_dib_to_bmp(void **data, UINT *size)
700 {
701 ULONG header_size;
702 ULONG count = 0;
703 ULONG offset;
704 BITMAPFILEHEADER *header;
705 BYTE *new_data;
706 UINT new_size;
707
708 if ((*size < 4) || (*size < (header_size = *(ULONG*)*data)))
709 return FALSE;
710
711 if ((header_size == sizeof(BITMAPINFOHEADER)) ||
712 (header_size == sizeof(BITMAPV4HEADER)) ||
713 (header_size == sizeof(BITMAPV5HEADER)) ||
714 (header_size == 64 /* sizeof(BITMAPCOREHEADER2) */))
715 {
716 /* All structures begin with the same memory layout as BITMAPINFOHEADER */
717 BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER*)*data;
718 count = info_header->biClrUsed;
719
720 if (!count && info_header->biBitCount <= 8)
721 count = 1 << info_header->biBitCount;
722
723 offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBQUAD) * count;
724
725 /* For BITMAPINFOHEADER with BI_BITFIELDS compression, there are 3 additional color masks after header */
726 if ((info_header->biSize == sizeof(BITMAPINFOHEADER)) && (info_header->biCompression == BI_BITFIELDS))
727 offset += 3 * sizeof(DWORD);
728 }
729 else if (header_size == sizeof(BITMAPCOREHEADER))
730 {
731 BITMAPCOREHEADER *core_header = (BITMAPCOREHEADER*)*data;
732
733 if (core_header->bcBitCount <= 8)
734 count = 1 << core_header->bcBitCount;
735
736 offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBTRIPLE) * count;
737 }
738 else
739 {
740 return FALSE;
741 }
742
743 TRACE("Converting DIB file to BMP\n");
744
745 new_size = *size + sizeof(BITMAPFILEHEADER);
746 new_data = HeapAlloc(GetProcessHeap(), 0, new_size);
747 CopyMemory(new_data + sizeof(BITMAPFILEHEADER), *data, *size);
748
749 /* Add BMP header */
750 header = (BITMAPFILEHEADER*)new_data;
751 header->bfType = 0x4d42; /* BM */
752 header->bfSize = new_size;
753 header->bfReserved1 = 0;
754 header->bfReserved2 = 0;
755 header->bfOffBits = offset;
756
757 /* Update input data */
758 *data = new_data;
759 *size = new_size;
760
761 return TRUE;
762 }
763
764 /************************************************************
765 * D3DXGetImageInfoFromFileInMemory
766 *
767 * Fills a D3DXIMAGE_INFO structure with info about an image
768 *
769 * PARAMS
770 * data [I] pointer to the image file data
771 * datasize [I] size of the passed data
772 * info [O] pointer to the destination structure
773 *
774 * RETURNS
775 * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or
776 * if info is NULL and data and datasize are not NULL
777 * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL
778 * D3DERR_INVALIDCALL, if data is NULL or
779 * if datasize is 0
780 *
781 * NOTES
782 * datasize may be bigger than the actual file size
783 *
784 */
785 HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info)
786 {
787 IWICImagingFactory *factory;
788 IWICBitmapDecoder *decoder = NULL;
789 IWICStream *stream;
790 HRESULT hr;
791 HRESULT initresult;
792 BOOL dib;
793
794 TRACE("(%p, %d, %p)\n", data, datasize, info);
795
796 if (!data || !datasize)
797 return D3DERR_INVALIDCALL;
798
799 if (!info)
800 return D3D_OK;
801
802 if ((datasize >= 4) && !strncmp(data, "DDS ", 4)) {
803 TRACE("File type is DDS\n");
804 return get_image_info_from_dds(data, datasize, info);
805 }
806
807 /* In case of DIB file, convert it to BMP */
808 dib = convert_dib_to_bmp((void**)&data, &datasize);
809
810 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
811
812 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory);
813
814 if (SUCCEEDED(hr)) {
815 IWICImagingFactory_CreateStream(factory, &stream);
816 IWICStream_InitializeFromMemory(stream, (BYTE*)data, datasize);
817 hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
818 IWICStream_Release(stream);
819 IWICImagingFactory_Release(factory);
820 }
821
822 if (FAILED(hr)) {
823 if ((datasize >= 2) && (!strncmp(data, "P3", 2) || !strncmp(data, "P6", 2)))
824 FIXME("File type PPM is not supported yet\n");
825 else if ((datasize >= 10) && !strncmp(data, "#?RADIANCE", 10))
826 FIXME("File type HDR is not supported yet\n");
827 else if ((datasize >= 2) && (!strncmp(data, "PF", 2) || !strncmp(data, "Pf", 2)))
828 FIXME("File type PFM is not supported yet\n");
829 }
830
831 if (SUCCEEDED(hr)) {
832 GUID container_format;
833 UINT frame_count;
834
835 hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format);
836 if (SUCCEEDED(hr)) {
837 if (IsEqualGUID(&container_format, &GUID_ContainerFormatBmp)) {
838 if (dib) {
839 TRACE("File type is DIB\n");
840 info->ImageFileFormat = D3DXIFF_DIB;
841 } else {
842 TRACE("File type is BMP\n");
843 info->ImageFileFormat = D3DXIFF_BMP;
844 }
845 } else if (IsEqualGUID(&container_format, &GUID_ContainerFormatPng)) {
846 TRACE("File type is PNG\n");
847 info->ImageFileFormat = D3DXIFF_PNG;
848 } else if(IsEqualGUID(&container_format, &GUID_ContainerFormatJpeg)) {
849 TRACE("File type is JPG\n");
850 info->ImageFileFormat = D3DXIFF_JPG;
851 } else if(IsEqualGUID(&container_format, &GUID_WineContainerFormatTga)) {
852 TRACE("File type is TGA\n");
853 info->ImageFileFormat = D3DXIFF_TGA;
854 } else {
855 WARN("Unsupported image file format %s\n", debugstr_guid(&container_format));
856 hr = D3DXERR_INVALIDDATA;
857 }
858 }
859
860 if (SUCCEEDED(hr))
861 hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
862 if (SUCCEEDED(hr) && !frame_count)
863 hr = D3DXERR_INVALIDDATA;
864
865 if (SUCCEEDED(hr)) {
866 IWICBitmapFrameDecode *frame = NULL;
867
868 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
869
870 if (SUCCEEDED(hr))
871 hr = IWICBitmapFrameDecode_GetSize(frame, &info->Width, &info->Height);
872
873 if (SUCCEEDED(hr)) {
874 WICPixelFormatGUID pixel_format;
875
876 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &pixel_format);
877 if (SUCCEEDED(hr)) {
878 info->Format = wic_guid_to_d3dformat(&pixel_format);
879 if (info->Format == D3DFMT_UNKNOWN) {
880 WARN("Unsupported pixel format %s\n", debugstr_guid(&pixel_format));
881 hr = D3DXERR_INVALIDDATA;
882 }
883 }
884 }
885
886 if (frame)
887 IWICBitmapFrameDecode_Release(frame);
888
889 info->Depth = 1;
890 info->MipLevels = 1;
891 info->ResourceType = D3DRTYPE_TEXTURE;
892 }
893 }
894
895 if (decoder)
896 IWICBitmapDecoder_Release(decoder);
897
898 if (SUCCEEDED(initresult))
899 CoUninitialize();
900
901 if (dib)
902 HeapFree(GetProcessHeap(), 0, (void*)data);
903
904 if (FAILED(hr)) {
905 TRACE("Invalid or unsupported image file\n");
906 return D3DXERR_INVALIDDATA;
907 }
908
909 return D3D_OK;
910 }
911
912 /************************************************************
913 * D3DXGetImageInfoFromFile
914 *
915 * RETURNS
916 * Success: D3D_OK, if we successfully load a valid image file or
917 * if we successfully load a file which is no valid image and info is NULL
918 * Failure: D3DXERR_INVALIDDATA, if we fail to load file or
919 * if file is not a valid image file and info is not NULL
920 * D3DERR_INVALIDCALL, if file is NULL
921 *
922 */
923 HRESULT WINAPI D3DXGetImageInfoFromFileA(const char *file, D3DXIMAGE_INFO *info)
924 {
925 WCHAR *widename;
926 HRESULT hr;
927 int strlength;
928
929 TRACE("file %s, info %p.\n", debugstr_a(file), info);
930
931 if( !file ) return D3DERR_INVALIDCALL;
932
933 strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
934 widename = HeapAlloc(GetProcessHeap(), 0, strlength * sizeof(*widename));
935 MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength);
936
937 hr = D3DXGetImageInfoFromFileW(widename, info);
938 HeapFree(GetProcessHeap(), 0, widename);
939
940 return hr;
941 }
942
943 HRESULT WINAPI D3DXGetImageInfoFromFileW(const WCHAR *file, D3DXIMAGE_INFO *info)
944 {
945 void *buffer;
946 HRESULT hr;
947 DWORD size;
948
949 TRACE("file %s, info %p.\n", debugstr_w(file), info);
950
951 if (!file)
952 return D3DERR_INVALIDCALL;
953
954 if (FAILED(map_view_of_file(file, &buffer, &size)))
955 return D3DXERR_INVALIDDATA;
956
957 hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info);
958 UnmapViewOfFile(buffer);
959
960 return hr;
961 }
962
963 /************************************************************
964 * D3DXGetImageInfoFromResource
965 *
966 * RETURNS
967 * Success: D3D_OK, if resource is a valid image file
968 * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or
969 * if we fail to load resource
970 *
971 */
972 HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, const char *resource, D3DXIMAGE_INFO *info)
973 {
974 HRSRC resinfo;
975 void *buffer;
976 DWORD size;
977
978 TRACE("module %p, resource %s, info %p.\n", module, debugstr_a(resource), info);
979
980 if (!(resinfo = FindResourceA(module, resource, (const char *)RT_RCDATA))
981 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */
982 && !(resinfo = FindResourceA(module, resource, (const char *)RT_BITMAP)))
983 return D3DXERR_INVALIDDATA;
984
985 if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size)))
986 return D3DXERR_INVALIDDATA;
987
988 return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
989 }
990
991 HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, D3DXIMAGE_INFO *info)
992 {
993 HRSRC resinfo;
994 void *buffer;
995 DWORD size;
996
997 TRACE("module %p, resource %s, info %p.\n", module, debugstr_w(resource), info);
998
999 if (!(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA))
1000 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */
1001 && !(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP)))
1002 return D3DXERR_INVALIDDATA;
1003
1004 if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size)))
1005 return D3DXERR_INVALIDDATA;
1006
1007 return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
1008 }
1009
1010 /************************************************************
1011 * D3DXLoadSurfaceFromFileInMemory
1012 *
1013 * Loads data from a given buffer into a surface and fills a given
1014 * D3DXIMAGE_INFO structure with info about the source data.
1015 *
1016 * PARAMS
1017 * pDestSurface [I] pointer to the surface
1018 * pDestPalette [I] palette to use
1019 * pDestRect [I] to be filled area of the surface
1020 * pSrcData [I] pointer to the source data
1021 * SrcDataSize [I] size of the source data in bytes
1022 * pSrcRect [I] area of the source data to load
1023 * dwFilter [I] filter to apply on stretching
1024 * Colorkey [I] colorkey
1025 * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure
1026 *
1027 * RETURNS
1028 * Success: D3D_OK
1029 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcData or SrcDataSize are NULL
1030 * D3DXERR_INVALIDDATA, if pSrcData is no valid image file
1031 *
1032 */
1033 HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface,
1034 const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize,
1035 const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo)
1036 {
1037 D3DXIMAGE_INFO imginfo;
1038 HRESULT hr, com_init;
1039
1040 IWICImagingFactory *factory = NULL;
1041 IWICBitmapDecoder *decoder;
1042 IWICBitmapFrameDecode *bitmapframe;
1043 IWICStream *stream;
1044
1045 const struct pixel_format_desc *formatdesc;
1046 WICRect wicrect;
1047 RECT rect;
1048
1049 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, "
1050 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n",
1051 pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize,
1052 wine_dbgstr_rect(pSrcRect), dwFilter, Colorkey, pSrcInfo);
1053
1054 if (!pDestSurface || !pSrcData || !SrcDataSize)
1055 return D3DERR_INVALIDCALL;
1056
1057 hr = D3DXGetImageInfoFromFileInMemory(pSrcData, SrcDataSize, &imginfo);
1058
1059 if (FAILED(hr))
1060 return hr;
1061
1062 if (pSrcRect)
1063 {
1064 wicrect.X = pSrcRect->left;
1065 wicrect.Y = pSrcRect->top;
1066 wicrect.Width = pSrcRect->right - pSrcRect->left;
1067 wicrect.Height = pSrcRect->bottom - pSrcRect->top;
1068 }
1069 else
1070 {
1071 wicrect.X = 0;
1072 wicrect.Y = 0;
1073 wicrect.Width = imginfo.Width;
1074 wicrect.Height = imginfo.Height;
1075 }
1076
1077 SetRect(&rect, 0, 0, wicrect.Width, wicrect.Height);
1078
1079 if (imginfo.ImageFileFormat == D3DXIFF_DDS)
1080 {
1081 hr = load_surface_from_dds(pDestSurface, pDestPalette, pDestRect, pSrcData, &rect,
1082 dwFilter, Colorkey, &imginfo);
1083 if (SUCCEEDED(hr) && pSrcInfo)
1084 *pSrcInfo = imginfo;
1085 return hr;
1086 }
1087
1088 if (imginfo.ImageFileFormat == D3DXIFF_DIB)
1089 convert_dib_to_bmp((void**)&pSrcData, &SrcDataSize);
1090
1091 com_init = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1092
1093 if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory)))
1094 goto cleanup_err;
1095
1096 if (FAILED(IWICImagingFactory_CreateStream(factory, &stream)))
1097 {
1098 IWICImagingFactory_Release(factory);
1099 factory = NULL;
1100 goto cleanup_err;
1101 }
1102
1103 IWICStream_InitializeFromMemory(stream, (BYTE*)pSrcData, SrcDataSize);
1104
1105 hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
1106
1107 IWICStream_Release(stream);
1108
1109 if (FAILED(hr))
1110 goto cleanup_err;
1111
1112 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &bitmapframe);
1113
1114 if (FAILED(hr))
1115 goto cleanup_bmp;
1116
1117 formatdesc = get_format_info(imginfo.Format);
1118
1119 if (formatdesc->type == FORMAT_UNKNOWN)
1120 {
1121 FIXME("Unsupported pixel format\n");
1122 hr = D3DXERR_INVALIDDATA;
1123 }
1124 else
1125 {
1126 BYTE *buffer;
1127 DWORD pitch;
1128 PALETTEENTRY *palette = NULL;
1129 WICColor *colors = NULL;
1130
1131 pitch = formatdesc->bytes_per_pixel * wicrect.Width;
1132 buffer = HeapAlloc(GetProcessHeap(), 0, pitch * wicrect.Height);
1133
1134 hr = IWICBitmapFrameDecode_CopyPixels(bitmapframe, &wicrect, pitch,
1135 pitch * wicrect.Height, buffer);
1136
1137 if (SUCCEEDED(hr) && (formatdesc->type == FORMAT_INDEX))
1138 {
1139 IWICPalette *wic_palette = NULL;
1140 UINT nb_colors;
1141
1142 hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
1143 if (SUCCEEDED(hr))
1144 hr = IWICBitmapFrameDecode_CopyPalette(bitmapframe, wic_palette);
1145 if (SUCCEEDED(hr))
1146 hr = IWICPalette_GetColorCount(wic_palette, &nb_colors);
1147 if (SUCCEEDED(hr))
1148 {
1149 colors = HeapAlloc(GetProcessHeap(), 0, nb_colors * sizeof(colors[0]));
1150 palette = HeapAlloc(GetProcessHeap(), 0, nb_colors * sizeof(palette[0]));
1151 if (!colors || !palette)
1152 hr = E_OUTOFMEMORY;
1153 }
1154 if (SUCCEEDED(hr))
1155 hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors);
1156 if (SUCCEEDED(hr))
1157 {
1158 UINT i;
1159
1160 /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */
1161 for (i = 0; i < nb_colors; i++)
1162 {
1163 palette[i].peRed = (colors[i] >> 16) & 0xff;
1164 palette[i].peGreen = (colors[i] >> 8) & 0xff;
1165 palette[i].peBlue = colors[i] & 0xff;
1166 palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */
1167 }
1168 }
1169 if (wic_palette)
1170 IWICPalette_Release(wic_palette);
1171 }
1172
1173 if (SUCCEEDED(hr))
1174 {
1175 hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
1176 buffer, imginfo.Format, pitch,
1177 palette, &rect, dwFilter, Colorkey);
1178 }
1179
1180 HeapFree(GetProcessHeap(), 0, colors);
1181 HeapFree(GetProcessHeap(), 0, palette);
1182 HeapFree(GetProcessHeap(), 0, buffer);
1183 }
1184
1185 IWICBitmapFrameDecode_Release(bitmapframe);
1186
1187 cleanup_bmp:
1188 IWICBitmapDecoder_Release(decoder);
1189
1190 cleanup_err:
1191 if (factory)
1192 IWICImagingFactory_Release(factory);
1193
1194 if (SUCCEEDED(com_init))
1195 CoUninitialize();
1196
1197 if (imginfo.ImageFileFormat == D3DXIFF_DIB)
1198 HeapFree(GetProcessHeap(), 0, (void*)pSrcData);
1199
1200 if (FAILED(hr))
1201 return D3DXERR_INVALIDDATA;
1202
1203 if (pSrcInfo)
1204 *pSrcInfo = imginfo;
1205
1206 return D3D_OK;
1207 }
1208
1209 HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface,
1210 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const char *src_file,
1211 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info)
1212 {
1213 WCHAR *src_file_w;
1214 HRESULT hr;
1215 int strlength;
1216
1217 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, "
1218 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n",
1219 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_a(src_file),
1220 wine_dbgstr_rect(src_rect), filter, color_key, src_info);
1221
1222 if (!src_file || !dst_surface)
1223 return D3DERR_INVALIDCALL;
1224
1225 strlength = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0);
1226 src_file_w = HeapAlloc(GetProcessHeap(), 0, strlength * sizeof(*src_file_w));
1227 MultiByteToWideChar(CP_ACP, 0, src_file, -1, src_file_w, strlength);
1228
1229 hr = D3DXLoadSurfaceFromFileW(dst_surface, dst_palette, dst_rect,
1230 src_file_w, src_rect, filter, color_key, src_info);
1231 HeapFree(GetProcessHeap(), 0, src_file_w);
1232
1233 return hr;
1234 }
1235
1236 HRESULT WINAPI D3DXLoadSurfaceFromFileW(IDirect3DSurface9 *dst_surface,
1237 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const WCHAR *src_file,
1238 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info)
1239 {
1240 UINT data_size;
1241 void *data;
1242 HRESULT hr;
1243
1244 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, "
1245 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n",
1246 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_w(src_file),
1247 wine_dbgstr_rect(src_rect), filter, color_key, src_info);
1248
1249 if (!src_file || !dst_surface)
1250 return D3DERR_INVALIDCALL;
1251
1252 if (FAILED(map_view_of_file(src_file, &data, &data_size)))
1253 return D3DXERR_INVALIDDATA;
1254
1255 hr = D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect,
1256 data, data_size, src_rect, filter, color_key, src_info);
1257 UnmapViewOfFile(data);
1258
1259 return hr;
1260 }
1261
1262 HRESULT WINAPI D3DXLoadSurfaceFromResourceA(IDirect3DSurface9 *dst_surface,
1263 const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const char *resource,
1264 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info)
1265 {
1266 UINT data_size;
1267 HRSRC resinfo;
1268 void *data;
1269
1270 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, "
1271 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n",
1272 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_a(resource),
1273 wine_dbgstr_rect(src_rect), filter, color_key, src_info);
1274
1275 if (!dst_surface)
1276 return D3DERR_INVALIDCALL;
1277
1278 if (!(resinfo = FindResourceA(src_module, resource, (const char *)RT_RCDATA))
1279 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */
1280 && !(resinfo = FindResourceA(src_module, resource, (const char *)RT_BITMAP)))
1281 return D3DXERR_INVALIDDATA;
1282
1283 if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size)))
1284 return D3DXERR_INVALIDDATA;
1285
1286 return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect,
1287 data, data_size, src_rect, filter, color_key, src_info);
1288 }
1289
1290 HRESULT WINAPI D3DXLoadSurfaceFromResourceW(IDirect3DSurface9 *dst_surface,
1291 const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const WCHAR *resource,
1292 const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info)
1293 {
1294 UINT data_size;
1295 HRSRC resinfo;
1296 void *data;
1297
1298 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, "
1299 "src_rect %s, filter %#x, color_key 0x%08x, src_info %p.\n",
1300 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_w(resource),
1301 wine_dbgstr_rect(src_rect), filter, color_key, src_info);
1302
1303 if (!dst_surface)
1304 return D3DERR_INVALIDCALL;
1305
1306 if (!(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_RCDATA))
1307 /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */
1308 && !(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_BITMAP)))
1309 return D3DXERR_INVALIDDATA;
1310
1311 if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size)))
1312 return D3DXERR_INVALIDDATA;
1313
1314 return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect,
1315 data, data_size, src_rect, filter, color_key, src_info);
1316 }
1317
1318
1319 /************************************************************
1320 * helper functions for D3DXLoadSurfaceFromMemory
1321 */
1322 struct argb_conversion_info
1323 {
1324 const struct pixel_format_desc *srcformat;
1325 const struct pixel_format_desc *destformat;
1326 DWORD srcshift[4], destshift[4];
1327 DWORD srcmask[4], destmask[4];
1328 BOOL process_channel[4];
1329 DWORD channelmask;
1330 };
1331
1332 static void init_argb_conversion_info(const struct pixel_format_desc *srcformat, const struct pixel_format_desc *destformat, struct argb_conversion_info *info)
1333 {
1334 UINT i;
1335 ZeroMemory(info->process_channel, 4 * sizeof(BOOL));
1336 info->channelmask = 0;
1337
1338 info->srcformat = srcformat;
1339 info->destformat = destformat;
1340
1341 for(i = 0;i < 4;i++) {
1342 /* srcshift is used to extract the _relevant_ components */
1343 info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0);
1344
1345 /* destshift is used to move the components to the correct position */
1346 info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0);
1347
1348 info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i];
1349 info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i];
1350
1351 /* channelmask specifies bits which aren't used in the source format but in the destination one */
1352 if(destformat->bits[i]) {
1353 if(srcformat->bits[i]) info->process_channel[i] = TRUE;
1354 else info->channelmask |= info->destmask[i];
1355 }
1356 }
1357 }
1358
1359 /************************************************************
1360 * get_relevant_argb_components
1361 *
1362 * Extracts the relevant components from the source color and
1363 * drops the less significant bits if they aren't used by the destination format.
1364 */
1365 static void get_relevant_argb_components(const struct argb_conversion_info *info, DWORD col, DWORD *out)
1366 {
1367 UINT i = 0;
1368 for(;i < 4;i++)
1369 if(info->process_channel[i])
1370 out[i] = (col & info->srcmask[i]) >> info->srcshift[i];
1371 }
1372
1373 /************************************************************
1374 * make_argb_color
1375 *
1376 * Recombines the output of get_relevant_argb_components and converts
1377 * it to the destination format.
1378 */
1379 static DWORD make_argb_color(const struct argb_conversion_info *info, const DWORD *in)
1380 {
1381 UINT i;
1382 DWORD val = 0;
1383
1384 for(i = 0;i < 4;i++) {
1385 if(info->process_channel[i]) {
1386 /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */
1387 signed int shift;
1388 for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift;
1389 val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i];
1390 }
1391 }
1392 val |= info->channelmask; /* new channels are set to their maximal value */
1393 return val;
1394 }
1395
1396 /* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */
1397 static void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, struct vec4 *dst)
1398 {
1399 DWORD mask, tmp;
1400 unsigned int c;
1401
1402 for (c = 0; c < 4; ++c)
1403 {
1404 static const unsigned int component_offsets[4] = {3, 0, 1, 2};
1405 float *dst_component = (float *)dst + component_offsets[c];
1406
1407 if (format->bits[c])
1408 {
1409 mask = ~0u >> (32 - format->bits[c]);
1410
1411 memcpy(&tmp, src + format->shift[c] / 8,
1412 min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8));
1413
1414 if (format->type == FORMAT_ARGBF16)
1415 *dst_component = float_16_to_32(tmp);
1416 else if (format->type == FORMAT_ARGBF)
1417 *dst_component = *(float *)&tmp;
1418 else
1419 *dst_component = (float)((tmp >> format->shift[c] % 8) & mask) / mask;
1420 }
1421 else
1422 *dst_component = 1.0f;
1423 }
1424 }
1425
1426 /* It doesn't work for components bigger than 32 bits. */
1427 static void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, BYTE *dst)
1428 {
1429 DWORD v, mask32;
1430 unsigned int c, i;
1431
1432 memset(dst, 0, format->bytes_per_pixel);
1433
1434 for (c = 0; c < 4; ++c)
1435 {
1436 static const unsigned int component_offsets[4] = {3, 0, 1, 2};
1437 const float src_component = *((const float *)src + component_offsets[c]);
1438
1439 if (!format->bits[c])
1440 continue;
1441
1442 mask32 = ~0u >> (32 - format->bits[c]);
1443
1444 if (format->type == FORMAT_ARGBF16)
1445 v = float_32_to_16(src_component);
1446 else if (format->type == FORMAT_ARGBF)
1447 v = *(DWORD *)&src_component;
1448 else
1449 v = (DWORD)(src_component * ((1 << format->bits[c]) - 1) + 0.5f);
1450
1451 for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8)
1452 {
1453 BYTE mask, byte;
1454
1455 if (format->shift[c] > i)
1456 {
1457 mask = mask32 << (format->shift[c] - i);
1458 byte = (v << (format->shift[c] - i)) & mask;
1459 }
1460 else
1461 {
1462 mask = mask32 >> (i - format->shift[c]);
1463 byte = (v >> (i - format->shift[c])) & mask;
1464 }
1465 dst[i / 8] |= byte;
1466 }
1467 }
1468 }
1469
1470 /************************************************************
1471 * copy_pixels
1472 *
1473 * Copies the source buffer to the destination buffer.
1474 * Works for any pixel format.
1475 * The source and the destination must be block-aligned.
1476 */
1477 void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch,
1478 BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size,
1479 const struct pixel_format_desc *format)
1480 {
1481 UINT row, slice;
1482 BYTE *dst_addr;
1483 const BYTE *src_addr;
1484 UINT row_block_count = (size->width + format->block_width - 1) / format->block_width;
1485 UINT row_count = (size->height + format->block_height - 1) / format->block_height;
1486
1487 for (slice = 0; slice < size->depth; slice++)
1488 {
1489 src_addr = src + slice * src_slice_pitch;
1490 dst_addr = dst + slice * dst_slice_pitch;
1491
1492 for (row = 0; row < row_count; row++)
1493 {
1494 memcpy(dst_addr, src_addr, row_block_count * format->block_byte_count);
1495 src_addr += src_row_pitch;
1496 dst_addr += dst_row_pitch;
1497 }
1498 }
1499 }
1500
1501 /************************************************************
1502 * convert_argb_pixels
1503 *
1504 * Copies the source buffer to the destination buffer, performing
1505 * any necessary format conversion and color keying.
1506 * Pixels outsize the source rect are blacked out.
1507 * Works only for ARGB formats with 1 - 4 bytes per pixel.
1508 */
1509 void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size,
1510 const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch,
1511 const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key,
1512 const PALETTEENTRY *palette)
1513 {
1514 struct argb_conversion_info conv_info, ck_conv_info;
1515 const struct pixel_format_desc *ck_format = NULL;
1516 DWORD channels[4];
1517 UINT min_width, min_height, min_depth;
1518 UINT x, y, z;
1519
1520 ZeroMemory(channels, sizeof(channels));
1521 init_argb_conversion_info(src_format, dst_format, &conv_info);
1522
1523 min_width = min(src_size->width, dst_size->width);
1524 min_height = min(src_size->height, dst_size->height);
1525 min_depth = min(src_size->depth, dst_size->depth);
1526
1527 if (color_key)
1528 {
1529 /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */
1530 ck_format = get_format_info(D3DFMT_A8R8G8B8);
1531 init_argb_conversion_info(src_format, ck_format, &ck_conv_info);
1532 }
1533
1534 for (z = 0; z < min_depth; z++) {
1535 const BYTE *src_slice_ptr = src + z * src_slice_pitch;
1536 BYTE *dst_slice_ptr = dst + z * dst_slice_pitch;
1537
1538 for (y = 0; y < min_height; y++) {
1539 const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch;
1540 BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch;
1541
1542 for (x = 0; x < min_width; x++) {
1543 if (!src_format->to_rgba && !dst_format->from_rgba
1544 && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4)
1545 {
1546 DWORD val;
1547
1548 get_relevant_argb_components(&conv_info, *(DWORD *)src_ptr, channels);
1549 val = make_argb_color(&conv_info, channels);
1550
1551 if (color_key)
1552 {
1553 DWORD ck_pixel;
1554
1555 get_relevant_argb_components(&ck_conv_info, *(DWORD *)src_ptr, channels);
1556 ck_pixel = make_argb_color(&ck_conv_info, channels);
1557 if (ck_pixel == color_key)
1558 val &= ~conv_info.destmask[0];
1559 }
1560 memcpy(dst_ptr, &val, dst_format->bytes_per_pixel);
1561 }
1562 else
1563 {
1564 struct vec4 color, tmp;
1565
1566 format_to_vec4(src_format, src_ptr, &color);
1567 if (src_format->to_rgba)
1568 src_format->to_rgba(&color, &tmp, palette);
1569 else
1570 tmp = color;
1571
1572 if (ck_format)
1573 {
1574 DWORD ck_pixel;
1575
1576 format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel);
1577 if (ck_pixel == color_key)
1578 tmp.w = 0.0f;
1579 }
1580
1581 if (dst_format->from_rgba)
1582 dst_format->from_rgba(&tmp, &color);
1583 else
1584 color = tmp;
1585
1586 format_from_vec4(dst_format, &color, dst_ptr);
1587 }
1588
1589 src_ptr += src_format->bytes_per_pixel;
1590 dst_ptr += dst_format->bytes_per_pixel;
1591 }
1592
1593 if (src_size->width < dst_size->width) /* black out remaining pixels */
1594 memset(dst_ptr, 0, dst_format->bytes_per_pixel * (dst_size->width - src_size->width));
1595 }
1596
1597 if (src_size->height < dst_size->height) /* black out remaining pixels */
1598 memset(dst + src_size->height * dst_row_pitch, 0, dst_row_pitch * (dst_size->height - src_size->height));
1599 }
1600 if (src_size->depth < dst_size->depth) /* black out remaining pixels */
1601 memset(dst + src_size->depth * dst_slice_pitch, 0, dst_slice_pitch * (dst_size->depth - src_size->depth));
1602 }
1603
1604 /************************************************************
1605 * point_filter_argb_pixels
1606 *
1607 * Copies the source buffer to the destination buffer, performing
1608 * any necessary format conversion, color keying and stretching
1609 * using a point filter.
1610 * Works only for ARGB formats with 1 - 4 bytes per pixel.
1611 */
1612 void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size,
1613 const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch,
1614 const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key,
1615 const PALETTEENTRY *palette)
1616 {
1617 struct argb_conversion_info conv_info, ck_conv_info;
1618 const struct pixel_format_desc *ck_format = NULL;
1619 DWORD channels[4];
1620 UINT x, y, z;
1621
1622 ZeroMemory(channels, sizeof(channels));
1623 init_argb_conversion_info(src_format, dst_format, &conv_info);
1624
1625 if (color_key)
1626 {
1627 /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */
1628 ck_format = get_format_info(D3DFMT_A8R8G8B8);
1629 init_argb_conversion_info(src_format, ck_format, &ck_conv_info);
1630 }
1631
1632 for (z = 0; z < dst_size->depth; z++)
1633 {
1634 BYTE *dst_slice_ptr = dst + z * dst_slice_pitch;
1635 const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth);
1636
1637 for (y = 0; y < dst_size->height; y++)
1638 {
1639 BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch;
1640 const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height);
1641
1642 for (x = 0; x < dst_size->width; x++)
1643 {
1644 const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel;
1645
1646 if (!src_format->to_rgba && !dst_format->from_rgba
1647 && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4)
1648 {
1649 DWORD val;
1650
1651 get_relevant_argb_components(&conv_info, *(DWORD *)src_ptr, channels);
1652 val = make_argb_color(&conv_info, channels);
1653
1654 if (color_key)
1655 {
1656 DWORD ck_pixel;
1657
1658 get_relevant_argb_components(&ck_conv_info, *(DWORD *)src_ptr, channels);
1659 ck_pixel = make_argb_color(&ck_conv_info, channels);
1660 if (ck_pixel == color_key)
1661 val &= ~conv_info.destmask[0];
1662 }
1663 memcpy(dst_ptr, &val, dst_format->bytes_per_pixel);
1664 }
1665 else
1666 {
1667 struct vec4 color, tmp;
1668
1669 format_to_vec4(src_format, src_ptr, &color);
1670 if (src_format->to_rgba)
1671 src_format->to_rgba(&color, &tmp, palette);
1672 else
1673 tmp = color;
1674
1675 if (ck_format)
1676 {
1677 DWORD ck_pixel;
1678
1679 format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel);
1680 if (ck_pixel == color_key)
1681 tmp.w = 0.0f;
1682 }
1683
1684 if (dst_format->from_rgba)
1685 dst_format->from_rgba(&tmp, &color);
1686 else
1687 color = tmp;
1688
1689 format_from_vec4(dst_format, &color, dst_ptr);
1690 }
1691
1692 dst_ptr += dst_format->bytes_per_pixel;
1693 }
1694 }
1695 }
1696 }
1697
1698 /************************************************************
1699 * D3DXLoadSurfaceFromMemory
1700 *
1701 * Loads data from a given memory chunk into a surface,
1702 * applying any of the specified filters.
1703 *
1704 * PARAMS
1705 * pDestSurface [I] pointer to the surface
1706 * pDestPalette [I] palette to use
1707 * pDestRect [I] to be filled area of the surface
1708 * pSrcMemory [I] pointer to the source data
1709 * SrcFormat [I] format of the source pixel data
1710 * SrcPitch [I] number of bytes in a row
1711 * pSrcPalette [I] palette used in the source image
1712 * pSrcRect [I] area of the source data to load
1713 * dwFilter [I] filter to apply on stretching
1714 * Colorkey [I] colorkey
1715 *
1716 * RETURNS
1717 * Success: D3D_OK, if we successfully load the pixel data into our surface or
1718 * if pSrcMemory is NULL but the other parameters are valid
1719 * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or
1720 * if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or
1721 * if DestRect is invalid
1722 * D3DXERR_INVALIDDATA, if we fail to lock pDestSurface
1723 * E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid
1724 *
1725 * NOTES
1726 * pSrcRect specifies the dimensions of the source data;
1727 * negative values for pSrcRect are allowed as we're only looking at the width and height anyway.
1728 *
1729 */
1730 HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface,
1731 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory,
1732 D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect,
1733 DWORD filter, D3DCOLOR color_key)
1734 {
1735 const struct pixel_format_desc *srcformatdesc, *destformatdesc;
1736 D3DSURFACE_DESC surfdesc;
1737 D3DLOCKED_RECT lockrect;
1738 struct volume src_size, dst_size;
1739
1740 TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s %#x, 0x%08x)\n",
1741 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_memory, src_format,
1742 src_pitch, src_palette, wine_dbgstr_rect(src_rect), filter, color_key);
1743
1744 if (!dst_surface || !src_memory || !src_rect)
1745 {
1746 WARN("Invalid argument specified.\n");
1747 return D3DERR_INVALIDCALL;
1748 }
1749 if (src_format == D3DFMT_UNKNOWN
1750 || src_rect->left >= src_rect->right
1751 || src_rect->top >= src_rect->bottom)
1752 {
1753 WARN("Invalid src_format or src_rect.\n");
1754 return E_FAIL;
1755 }
1756
1757 if (filter == D3DX_DEFAULT)
1758 filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
1759
1760 IDirect3DSurface9_GetDesc(dst_surface, &surfdesc);
1761
1762 src_size.width = src_rect->right - src_rect->left;
1763 src_size.height = src_rect->bottom - src_rect->top;
1764 src_size.depth = 1;
1765 if (!dst_rect)
1766 {
1767 dst_size.width = surfdesc.Width;
1768 dst_size.height = surfdesc.Height;
1769 }
1770 else
1771 {
1772 if (dst_rect->left > dst_rect->right || dst_rect->right > surfdesc.Width
1773 || dst_rect->top > dst_rect->bottom || dst_rect->bottom > surfdesc.Height
1774 || dst_rect->left < 0 || dst_rect->top < 0)
1775 {
1776 WARN("Invalid dst_rect specified.\n");
1777 return D3DERR_INVALIDCALL;
1778 }
1779 dst_size.width = dst_rect->right - dst_rect->left;
1780 dst_size.height = dst_rect->bottom - dst_rect->top;
1781 if (!dst_size.width || !dst_size.height)
1782 return D3D_OK;
1783 }
1784 dst_size.depth = 1;
1785
1786 srcformatdesc = get_format_info(src_format);
1787 destformatdesc = get_format_info(surfdesc.Format);
1788 if (srcformatdesc->type == FORMAT_UNKNOWN || destformatdesc->type == FORMAT_UNKNOWN)
1789 {
1790 FIXME("Unsupported pixel format conversion %#x -> %#x\n", src_format, surfdesc.Format);
1791 return E_NOTIMPL;
1792 }
1793
1794 if (src_format == surfdesc.Format
1795 && dst_size.width == src_size.width
1796 && dst_size.height == src_size.height
1797 && color_key == 0) /* Simple copy. */
1798 {
1799 if (src_rect->left & (srcformatdesc->block_width - 1)
1800 || src_rect->top & (srcformatdesc->block_height - 1)
1801 || (src_rect->right & (srcformatdesc->block_width - 1)
1802 && src_size.width != surfdesc.Width)
1803 || (src_rect->bottom & (srcformatdesc->block_height - 1)
1804 && src_size.height != surfdesc.Height))
1805 {
1806 WARN("Source rect %s is misaligned.\n", wine_dbgstr_rect(src_rect));
1807 return D3DXERR_INVALIDDATA;
1808 }
1809
1810 if (FAILED(IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
1811 return D3DXERR_INVALIDDATA;
1812
1813 copy_pixels(src_memory, src_pitch, 0, lockrect.pBits, lockrect.Pitch, 0,
1814 &src_size, srcformatdesc);
1815
1816 IDirect3DSurface9_UnlockRect(dst_surface);
1817 }
1818 else /* Stretching or format conversion. */
1819 {
1820 if (((srcformatdesc->type != FORMAT_ARGB) && (srcformatdesc->type != FORMAT_INDEX)) ||
1821 (destformatdesc->type != FORMAT_ARGB))
1822 {
1823 FIXME("Format conversion missing %#x -> %#x\n", src_format, surfdesc.Format);
1824 return E_NOTIMPL;
1825 }
1826
1827 if (FAILED(IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
1828 return D3DXERR_INVALIDDATA;
1829
1830 if ((filter & 0xf) == D3DX_FILTER_NONE)
1831 {
1832 convert_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc,
1833 lockrect.pBits, lockrect.Pitch, 0, &dst_size, destformatdesc, color_key, src_palette);
1834 }
1835 else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */
1836 {
1837 if ((filter & 0xf) != D3DX_FILTER_POINT)
1838 FIXME("Unhandled filter %#x.\n", filter);
1839
1840 /* Always apply a point filter until D3DX_FILTER_LINEAR,
1841 * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */
1842 point_filter_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc,
1843 lockrect.pBits, lockrect.Pitch, 0, &dst_size, destformatdesc, color_key, src_palette);
1844 }
1845
1846 IDirect3DSurface9_UnlockRect(dst_surface);
1847 }
1848
1849 return D3D_OK;
1850 }
1851
1852 /************************************************************
1853 * D3DXLoadSurfaceFromSurface
1854 *
1855 * Copies the contents from one surface to another, performing any required
1856 * format conversion, resizing or filtering.
1857 *
1858 * PARAMS
1859 * pDestSurface [I] pointer to the destination surface
1860 * pDestPalette [I] palette to use
1861 * pDestRect [I] to be filled area of the surface
1862 * pSrcSurface [I] pointer to the source surface
1863 * pSrcPalette [I] palette used for the source surface
1864 * pSrcRect [I] area of the source data to load
1865 * dwFilter [I] filter to apply on resizing
1866 * Colorkey [I] any ARGB value or 0 to disable color-keying
1867 *
1868 * RETURNS
1869 * Success: D3D_OK
1870 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
1871 * D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
1872 *
1873 */
1874 HRESULT WINAPI D3DXLoadSurfaceFromSurface(IDirect3DSurface9 *dst_surface,
1875 const PALETTEENTRY *dst_palette, const RECT *dst_rect, IDirect3DSurface9 *src_surface,
1876 const PALETTEENTRY *src_palette, const RECT *src_rect, DWORD filter, D3DCOLOR color_key)
1877 {
1878 RECT rect;
1879 D3DLOCKED_RECT lock;
1880 D3DSURFACE_DESC SrcDesc;
1881 HRESULT hr;
1882
1883 TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_surface %p, "
1884 "src_palette %p, src_rect %s, filter %#x, color_key 0x%08x.\n",
1885 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_surface,
1886 src_palette, wine_dbgstr_rect(src_rect), filter, color_key);
1887
1888 if (!dst_surface || !src_surface)
1889 return D3DERR_INVALIDCALL;
1890
1891 IDirect3DSurface9_GetDesc(src_surface, &SrcDesc);
1892
1893 if (!src_rect)
1894 SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height);
1895 else
1896 rect = *src_rect;
1897
1898 if (FAILED(IDirect3DSurface9_LockRect(src_surface, &lock, NULL, D3DLOCK_READONLY)))
1899 return D3DXERR_INVALIDDATA;
1900
1901 hr = D3DXLoadSurfaceFromMemory(dst_surface, dst_palette, dst_rect,
1902 lock.pBits, SrcDesc.Format, lock.Pitch, src_palette, &rect, filter, color_key);
1903
1904 IDirect3DSurface9_UnlockRect(src_surface);
1905
1906 return hr;
1907 }
1908
1909
1910 HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1911 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1912 {
1913 int len;
1914 WCHAR *filename;
1915 HRESULT hr;
1916 ID3DXBuffer *buffer;
1917
1918 TRACE("(%s, %#x, %p, %p, %s): relay\n",
1919 wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
1920
1921 if (!dst_filename) return D3DERR_INVALIDCALL;
1922
1923 len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0);
1924 filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1925 if (!filename) return E_OUTOFMEMORY;
1926 MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len);
1927
1928 hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect);
1929 if (SUCCEEDED(hr))
1930 {
1931 hr = write_buffer_to_file(filename, buffer);
1932 ID3DXBuffer_Release(buffer);
1933 }
1934
1935 HeapFree(GetProcessHeap(), 0, filename);
1936 return hr;
1937 }
1938
1939 HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1940 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1941 {
1942 HRESULT hr;
1943 ID3DXBuffer *buffer;
1944
1945 TRACE("(%s, %#x, %p, %p, %s): relay\n",
1946 wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
1947
1948 if (!dst_filename) return D3DERR_INVALIDCALL;
1949
1950 hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect);
1951 if (SUCCEEDED(hr))
1952 {
1953 hr = write_buffer_to_file(dst_filename, buffer);
1954 ID3DXBuffer_Release(buffer);
1955 }
1956
1957 return hr;
1958 }
1959
1960 HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format,
1961 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1962 {
1963 IWICBitmapEncoder *encoder = NULL;
1964 IWICBitmapFrameEncode *frame = NULL;
1965 IPropertyBag2 *encoder_options = NULL;
1966 IStream *stream = NULL;
1967 HRESULT hr;
1968 HRESULT initresult;
1969 const CLSID *encoder_clsid;
1970 const GUID *pixel_format_guid;
1971 WICPixelFormatGUID wic_pixel_format;
1972 D3DFORMAT d3d_pixel_format;
1973 D3DSURFACE_DESC src_surface_desc;
1974 D3DLOCKED_RECT locked_rect;
1975 int width, height;
1976 STATSTG stream_stats;
1977 HGLOBAL stream_hglobal;
1978 ID3DXBuffer *buffer;
1979 DWORD size;
1980
1981 TRACE("(%p, %#x, %p, %p, %s)\n",
1982 dst_buffer, file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
1983
1984 if (!dst_buffer || !src_surface) return D3DERR_INVALIDCALL;
1985
1986 if (src_palette)
1987 {
1988 FIXME("Saving surfaces with palettized pixel formats not implemented yet\n");
1989 return D3DERR_INVALIDCALL;
1990 }
1991
1992 switch (file_format)
1993 {
1994 case D3DXIFF_BMP:
1995 case D3DXIFF_DIB:
1996 encoder_clsid = &CLSID_WICBmpEncoder;
1997 break;
1998 case D3DXIFF_PNG:
1999 encoder_clsid = &CLSID_WICPngEncoder;
2000 break;
2001 case D3DXIFF_JPG:
2002 encoder_clsid = &CLSID_WICJpegEncoder;
2003 break;
2004 case D3DXIFF_DDS:
2005 return save_dds_surface_to_memory(dst_buffer, src_surface, src_rect);
2006 case D3DXIFF_HDR:
2007 case D3DXIFF_PFM:
2008 case D3DXIFF_TGA:
2009 case D3DXIFF_PPM:
2010 FIXME("File format %#x is not supported yet\n", file_format);
2011 return E_NOTIMPL;
2012 default:
2013 return D3DERR_INVALIDCALL;
2014 }
2015
2016 IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc);
2017 if (src_rect)
2018 {
2019 if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom)
2020 {
2021 WARN("Invalid rectangle with 0 area\n");
2022 return D3DXCreateBuffer(64, dst_buffer);
2023 }
2024 if (src_rect->left < 0 || src_rect->top < 0)
2025 return D3DERR_INVALIDCALL;
2026 if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom)
2027 return D3DERR_INVALIDCALL;
2028 if (src_rect->right > src_surface_desc.Width || src_rect->bottom > src_surface_desc.Height)
2029 return D3DERR_INVALIDCALL;
2030
2031 width = src_rect->right - src_rect->left;
2032 height = src_rect->bottom - src_rect->top;
2033 }
2034 else
2035 {
2036 width = src_surface_desc.Width;
2037 height = src_surface_desc.Height;
2038 }
2039
2040 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2041
2042 hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER,
2043 &IID_IWICBitmapEncoder, (void **)&encoder);
2044 if (FAILED(hr)) goto cleanup_err;
2045
2046 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2047 if (FAILED(hr)) goto cleanup_err;
2048
2049 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
2050 if (FAILED(hr)) goto cleanup_err;
2051
2052 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options);
2053 if (FAILED(hr)) goto cleanup_err;
2054
2055 hr = IWICBitmapFrameEncode_Initialize(frame, encoder_options);
2056 if (FAILED(hr)) goto cleanup_err;
2057
2058 hr = IWICBitmapFrameEncode_SetSize(frame, width, height);
2059 if (FAILED(hr)) goto cleanup_err;
2060
2061 pixel_format_guid = d3dformat_to_wic_guid(src_surface_desc.Format);
2062 if (!pixel_format_guid)
2063 {
2064 FIXME("Pixel format %#x is not supported yet\n", src_surface_desc.Format);
2065 hr = E_NOTIMPL;
2066 goto cleanup;
2067 }
2068
2069 memcpy(&wic_pixel_format, pixel_format_guid, sizeof(GUID));
2070 hr = IWICBitmapFrameEncode_SetPixelFormat(frame, &wic_pixel_format);
2071 d3d_pixel_format = wic_guid_to_d3dformat(&wic_pixel_format);
2072 if (SUCCEEDED(hr) && d3d_pixel_format != D3DFMT_UNKNOWN)
2073 {
2074 TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format), d3d_pixel_format);
2075
2076 if (src_surface_desc.Format == d3d_pixel_format) /* Simple copy */
2077 {
2078 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY);
2079 if (SUCCEEDED(hr))
2080 {
2081 IWICBitmapFrameEncode_WritePixels(frame, height,
2082 locked_rect.Pitch, height * locked_rect.Pitch, locked_rect.pBits);
2083 IDirect3DSurface9_UnlockRect(src_surface);
2084 }
2085 }
2086 else /* Pixel format conversion */
2087 {
2088 const struct pixel_format_desc *src_format_desc, *dst_format_desc;
2089 struct volume size;
2090 DWORD dst_pitch;
2091 void *dst_data;
2092
2093 src_format_desc = get_format_info(src_surface_desc.Format);
2094 dst_format_desc = get_format_info(d3d_pixel_format);
2095 if (src_format_desc->type != FORMAT_ARGB || dst_format_desc->type != FORMAT_ARGB)
2096 {
2097 FIXME("Unsupported pixel format conversion %#x -> %#x\n",
2098 src_surface_desc.Format, d3d_pixel_format);
2099 hr = E_NOTIMPL;
2100 goto cleanup;
2101 }
2102
2103 size.width = width;
2104 size.height = height;
2105 size.depth = 1;
2106 dst_pitch = width * dst_format_desc->bytes_per_pixel;
2107 dst_data = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height);
2108 if (!dst_data)
2109 {
2110 hr = E_OUTOFMEMORY;
2111 goto cleanup;
2112 }
2113
2114 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY);
2115 if (SUCCEEDED(hr))
2116 {
2117 convert_argb_pixels(locked_rect.pBits, locked_rect.Pitch, 0, &size, src_format_desc,
2118 dst_data, dst_pitch, 0, &size, dst_format_desc, 0, NULL);
2119 IDirect3DSurface9_UnlockRect(src_surface);
2120 }
2121
2122 IWICBitmapFrameEncode_WritePixels(frame, height, dst_pitch, dst_pitch * height, dst_data);
2123 HeapFree(GetProcessHeap(), 0, dst_data);
2124 }
2125
2126 hr = IWICBitmapFrameEncode_Commit(frame);
2127 if (SUCCEEDED(hr)) hr = IWICBitmapEncoder_Commit(encoder);
2128 }
2129 else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format);
2130
2131 /* copy data from stream to ID3DXBuffer */
2132 hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME);
2133 if (FAILED(hr)) goto cleanup_err;
2134
2135 if (stream_stats.cbSize.u.HighPart != 0)
2136 {
2137 hr = D3DXERR_INVALIDDATA;
2138 goto cleanup;
2139 }
2140 size = stream_stats.cbSize.u.LowPart;
2141
2142 /* Remove BMP header for DIB */
2143 if (file_format == D3DXIFF_DIB)
2144 size -= sizeof(BITMAPFILEHEADER);
2145
2146 hr = D3DXCreateBuffer(size, &buffer);
2147 if (FAILED(hr)) goto cleanup;
2148
2149 hr = GetHGlobalFromStream(stream, &stream_hglobal);
2150 if (SUCCEEDED(hr))
2151 {
2152 void *buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
2153 void *stream_data = GlobalLock(stream_hglobal);
2154 /* Remove BMP header for DIB */
2155 if (file_format == D3DXIFF_DIB)
2156 stream_data = (void*)((BYTE*)stream_data + sizeof(BITMAPFILEHEADER));
2157 memcpy(buffer_pointer, stream_data, size);
2158 GlobalUnlock(stream_hglobal);
2159 *dst_buffer = buffer;
2160 }
2161 else ID3DXBuffer_Release(buffer);
2162
2163 cleanup_err:
2164 if (FAILED(hr) && hr != E_OUTOFMEMORY)
2165 hr = D3DERR_INVALIDCALL;
2166
2167 cleanup:
2168 if (stream) IStream_Release(stream);
2169
2170 if (frame) IWICBitmapFrameEncode_Release(frame);
2171 if (encoder_options) IPropertyBag2_Release(encoder_options);
2172
2173 if (encoder) IWICBitmapEncoder_Release(encoder);
2174
2175 if (SUCCEEDED(initresult)) CoUninitialize();
2176
2177 return hr;
2178 }