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