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