2 * Copyright (C) 2009-2010 Tony Wasserka
3 * Copyright (C) 2012 Józef Kucia
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.
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.
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
21 #include "wine/debug.h"
22 #include "wine/unicode.h"
23 #include "d3dx9_36_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
31 /* Wine-specific WIC GUIDs */
32 DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22);
38 } wic_pixel_formats[] = {
39 { &GUID_WICPixelFormat8bppIndexed, D3DFMT_L8 },
40 { &GUID_WICPixelFormat1bppIndexed, D3DFMT_L8 },
41 { &GUID_WICPixelFormat4bppIndexed, D3DFMT_L8 },
42 { &GUID_WICPixelFormat16bppBGR555, D3DFMT_X1R5G5B5 },
43 { &GUID_WICPixelFormat16bppBGR565, D3DFMT_R5G6B5 },
44 { &GUID_WICPixelFormat24bppBGR, D3DFMT_R8G8B8 },
45 { &GUID_WICPixelFormat32bppBGR, D3DFMT_X8R8G8B8 },
46 { &GUID_WICPixelFormat32bppBGRA, D3DFMT_A8R8G8B8 }
49 static D3DFORMAT wic_guid_to_d3dformat(const GUID *guid)
53 for (i = 0; i < sizeof(wic_pixel_formats) / sizeof(wic_pixel_formats[0]); i++)
55 if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid))
56 return wic_pixel_formats[i].d3dformat;
59 return D3DFMT_UNKNOWN;
62 static const GUID *d3dformat_to_wic_guid(D3DFORMAT format)
66 for (i = 0; i < sizeof(wic_pixel_formats) / sizeof(wic_pixel_formats[0]); i++)
68 if (wic_pixel_formats[i].d3dformat == format)
69 return wic_pixel_formats[i].wic_guid;
75 /* dds_header.flags */
77 #define DDS_HEIGHT 0x2
80 #define DDS_PIXELFORMAT 0x1000
81 #define DDS_MIPMAPCOUNT 0x20000
82 #define DDS_LINEARSIZE 0x80000
83 #define DDS_DEPTH 0x800000
86 #define DDS_CAPS_COMPLEX 0x8
87 #define DDS_CAPS_TEXTURE 0x1000
88 #define DDS_CAPS_MIPMAP 0x400000
90 /* dds_header.caps2 */
91 #define DDS_CAPS2_CUBEMAP 0x200
92 #define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400
93 #define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800
94 #define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000
95 #define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000
96 #define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000
97 #define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000
98 #define DDS_CAPS2_VOLUME 0x200000
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
108 struct dds_pixel_format
127 DWORD pitch_or_linear_size;
131 struct dds_pixel_format pixel_format;
139 static D3DFORMAT dds_fourcc_to_d3dformat(DWORD fourcc)
142 static const DWORD known_fourcc[] = {
143 MAKEFOURCC('U','Y','V','Y'),
144 MAKEFOURCC('Y','U','Y','2'),
145 MAKEFOURCC('R','G','B','G'),
146 MAKEFOURCC('G','R','G','B'),
147 MAKEFOURCC('D','X','T','1'),
148 MAKEFOURCC('D','X','T','2'),
149 MAKEFOURCC('D','X','T','3'),
150 MAKEFOURCC('D','X','T','4'),
151 MAKEFOURCC('D','X','T','5')
154 for (i = 0; i < sizeof(known_fourcc) / sizeof(known_fourcc[0]); i++)
156 if (known_fourcc[i] == fourcc)
160 WARN("Unknown FourCC %#x\n", fourcc);
161 return D3DFMT_UNKNOWN;
164 static D3DFORMAT dds_rgb_to_d3dformat(const struct dds_pixel_format *pixel_format)
167 static const struct {
174 } rgb_pixel_formats[] = {
175 { 8, 0xe0, 0x1c, 0x03, 0, D3DFMT_R3G3B2 },
176 { 16, 0xf800, 0x07e0, 0x001f, 0x0000, D3DFMT_R5G6B5 },
177 { 16, 0x7c00, 0x03e0, 0x001f, 0x8000, D3DFMT_A1R5G5B5 },
178 { 16, 0x7c00, 0x03e0, 0x001f, 0x0000, D3DFMT_X1R5G5B5 },
179 { 16, 0x0f00, 0x00f0, 0x000f, 0xf000, D3DFMT_A4R4G4B4 },
180 { 16, 0x0f00, 0x00f0, 0x000f, 0x0000, D3DFMT_X4R4G4B4 },
181 { 16, 0x00e0, 0x001c, 0x0003, 0xff00, D3DFMT_A8R3G3B2 },
182 { 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000, D3DFMT_R8G8B8 },
183 { 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, D3DFMT_A8R8G8B8 },
184 { 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, D3DFMT_X8R8G8B8 },
185 { 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, D3DFMT_A2B10G10R10 },
186 { 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000, D3DFMT_A2R10G10B10 },
187 { 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000, D3DFMT_G16R16 },
190 for (i = 0; i < sizeof(rgb_pixel_formats) / sizeof(rgb_pixel_formats[0]); i++)
192 if (rgb_pixel_formats[i].bpp == pixel_format->bpp
193 && rgb_pixel_formats[i].rmask == pixel_format->rmask
194 && rgb_pixel_formats[i].gmask == pixel_format->gmask
195 && rgb_pixel_formats[i].bmask == pixel_format->bmask)
197 if ((pixel_format->flags & DDS_PF_ALPHA) && rgb_pixel_formats[i].amask == pixel_format->amask)
198 return rgb_pixel_formats[i].format;
199 if (rgb_pixel_formats[i].amask == 0)
200 return rgb_pixel_formats[i].format;
204 WARN("Unknown RGB pixel format (%#x, %#x, %#x, %#x)\n",
205 pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask);
206 return D3DFMT_UNKNOWN;
209 static D3DFORMAT dds_luminance_to_d3dformat(const struct dds_pixel_format *pixel_format)
211 if (pixel_format->bpp == 8)
213 if (pixel_format->rmask == 0xff)
215 if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x0f && pixel_format->amask == 0xf0)
218 if (pixel_format->bpp == 16)
220 if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x00ff && pixel_format->amask == 0xff00)
224 WARN("Unknown luminance pixel format (bpp %#x, l %#x, a %#x)\n",
225 pixel_format->bpp, pixel_format->rmask, pixel_format->amask);
226 return D3DFMT_UNKNOWN;
229 static D3DFORMAT dds_alpha_to_d3dformat(const struct dds_pixel_format *pixel_format)
231 if (pixel_format->bpp == 8 && pixel_format->amask == 0xff)
234 WARN("Unknown Alpha pixel format (%#x, %#x)\n", pixel_format->bpp, pixel_format->rmask);
235 return D3DFMT_UNKNOWN;
238 static D3DFORMAT dds_pixel_format_to_d3dformat(const struct dds_pixel_format *pixel_format)
240 if (pixel_format->flags & DDS_PF_FOURCC)
241 return dds_fourcc_to_d3dformat(pixel_format->fourcc);
242 if (pixel_format->flags & DDS_PF_RGB)
243 return dds_rgb_to_d3dformat(pixel_format);
244 if (pixel_format->flags & DDS_PF_LUMINANCE)
245 return dds_luminance_to_d3dformat(pixel_format);
246 if (pixel_format->flags & DDS_PF_ALPHA_ONLY)
247 return dds_alpha_to_d3dformat(pixel_format);
249 WARN("Unknown pixel format (fourcc %#x, bpp %#x, r %#x, g %#x, b %#x, a %#x)\n",
250 pixel_format->fourcc, pixel_format->bpp, pixel_format->rmask, pixel_format->gmask,
251 pixel_format->bmask, pixel_format->amask);
252 return D3DFMT_UNKNOWN;
255 /************************************************************
256 * get_image_info_from_dds
258 * Fills a D3DXIMAGE_INFO structure with information
259 * about a DDS file stored in the memory.
262 * buffer [I] pointer to DDS data
263 * length [I] size of DDS data
264 * info [O] pointer to D3DXIMAGE_INFO structure
268 * Failure: D3DXERR_INVALIDDATA
271 static HRESULT get_image_info_from_dds(const void *buffer, DWORD length, D3DXIMAGE_INFO *info)
273 const struct dds_header *header = buffer;
275 if (length < sizeof(*header) || !info)
276 return D3DXERR_INVALIDDATA;
278 if (header->pixel_format.size != sizeof(header->pixel_format))
279 return D3DXERR_INVALIDDATA;
281 info->Width = header->width;
282 info->Height = header->height;
284 info->MipLevels = (header->flags & DDS_MIPMAPCOUNT) ? header->miplevels : 1;
286 info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format);
287 if (info->Format == D3DFMT_UNKNOWN)
288 return D3DXERR_INVALIDDATA;
290 if (header->caps2 & DDS_CAPS2_VOLUME)
292 info->Depth = header->depth;
293 info->ResourceType = D3DRTYPE_VOLUMETEXTURE;
295 else if (header->caps2 & DDS_CAPS2_CUBEMAP)
297 info->ResourceType = D3DRTYPE_CUBETEXTURE;
301 info->ResourceType = D3DRTYPE_TEXTURE;
304 info->ImageFileFormat = D3DXIFF_DDS;
309 /************************************************************
310 * D3DXGetImageInfoFromFileInMemory
312 * Fills a D3DXIMAGE_INFO structure with info about an image
315 * data [I] pointer to the image file data
316 * datasize [I] size of the passed data
317 * info [O] pointer to the destination structure
320 * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or
321 * if info is NULL and data and datasize are not NULL
322 * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL
323 * D3DERR_INVALIDCALL, if data is NULL or
327 * datasize may be bigger than the actual file size
330 HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(LPCVOID data, UINT datasize, D3DXIMAGE_INFO *info)
332 IWICImagingFactory *factory;
333 IWICBitmapDecoder *decoder = NULL;
338 TRACE("(%p, %d, %p)\n", data, datasize, info);
340 if (!data || !datasize)
341 return D3DERR_INVALIDCALL;
346 if ((datasize >= 4) && !strncmp(data, "DDS ", 4))
347 return get_image_info_from_dds(data, datasize, info);
349 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
351 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory);
354 IWICImagingFactory_CreateStream(factory, &stream);
355 IWICStream_InitializeFromMemory(stream, (BYTE*)data, datasize);
356 hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
357 IStream_Release(stream);
358 IWICImagingFactory_Release(factory);
362 if ((datasize >= 2) && (!strncmp(data, "P3", 2) || !strncmp(data, "P6", 2)))
363 FIXME("File type PPM is not supported yet\n");
364 else if ((datasize >= 2) && !strncmp(data, "BM", 2))
365 FIXME("File type DIB is not supported yet\n");
366 else if ((datasize >= 10) && !strncmp(data, "#?RADIANCE", 10))
367 FIXME("File type HDR is not supported yet\n");
368 else if ((datasize >= 2) && (!strncmp(data, "PF", 2) || !strncmp(data, "Pf", 2)))
369 FIXME("File type PFM is not supported yet\n");
373 GUID container_format;
376 hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format);
378 if (IsEqualGUID(&container_format, &GUID_ContainerFormatBmp)) {
379 TRACE("File type is BMP\n");
380 info->ImageFileFormat = D3DXIFF_BMP;
381 } else if (IsEqualGUID(&container_format, &GUID_ContainerFormatPng)) {
382 TRACE("File type is PNG\n");
383 info->ImageFileFormat = D3DXIFF_PNG;
384 } else if(IsEqualGUID(&container_format, &GUID_ContainerFormatJpeg)) {
385 TRACE("File type is JPG\n");
386 info->ImageFileFormat = D3DXIFF_JPG;
387 } else if(IsEqualGUID(&container_format, &GUID_WineContainerFormatTga)) {
388 TRACE("File type is TGA\n");
389 info->ImageFileFormat = D3DXIFF_TGA;
391 WARN("Unsupported image file format %s\n", debugstr_guid(&container_format));
392 hr = D3DXERR_INVALIDDATA;
397 hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
398 if (SUCCEEDED(hr) && !frame_count)
399 hr = D3DXERR_INVALIDDATA;
402 IWICBitmapFrameDecode *frame = NULL;
404 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
407 hr = IWICBitmapFrameDecode_GetSize(frame, &info->Width, &info->Height);
410 WICPixelFormatGUID pixel_format;
412 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &pixel_format);
414 info->Format = wic_guid_to_d3dformat(&pixel_format);
415 if (info->Format == D3DFMT_UNKNOWN) {
416 WARN("Unsupported pixel format %s\n", debugstr_guid(&pixel_format));
417 hr = D3DXERR_INVALIDDATA;
423 IWICBitmapFrameDecode_Release(frame);
427 info->ResourceType = D3DRTYPE_TEXTURE;
432 IWICBitmapDecoder_Release(decoder);
434 if (SUCCEEDED(initresult))
438 TRACE("Invalid or unsupported image file\n");
439 return D3DXERR_INVALIDDATA;
445 /************************************************************
446 * D3DXGetImageInfoFromFile
449 * Success: D3D_OK, if we successfully load a valid image file or
450 * if we successfully load a file which is no valid image and info is NULL
451 * Failure: D3DXERR_INVALIDDATA, if we fail to load file or
452 * if file is not a valid image file and info is not NULL
453 * D3DERR_INVALIDCALL, if file is NULL
456 HRESULT WINAPI D3DXGetImageInfoFromFileA(LPCSTR file, D3DXIMAGE_INFO *info)
462 TRACE("(%s, %p): relay\n", debugstr_a(file), info);
464 if( !file ) return D3DERR_INVALIDCALL;
466 strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
467 widename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlength * sizeof(WCHAR));
468 MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength);
470 hr = D3DXGetImageInfoFromFileW(widename, info);
471 HeapFree(GetProcessHeap(), 0, widename);
476 HRESULT WINAPI D3DXGetImageInfoFromFileW(LPCWSTR file, D3DXIMAGE_INFO *info)
482 TRACE("(%s, %p): relay\n", debugstr_w(file), info);
484 if( !file ) return D3DERR_INVALIDCALL;
486 hr = map_view_of_file(file, &buffer, &size);
487 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
489 hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info);
490 UnmapViewOfFile(buffer);
495 /************************************************************
496 * D3DXGetImageInfoFromResource
499 * Success: D3D_OK, if resource is a valid image file
500 * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or
501 * if we fail to load resource
504 HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, LPCSTR resource, D3DXIMAGE_INFO *info)
508 TRACE("(%p, %s, %p)\n", module, debugstr_a(resource), info);
510 resinfo = FindResourceA(module, resource, (LPCSTR)RT_RCDATA);
516 hr = load_resource_into_memory(module, resinfo, &buffer, &size);
517 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
518 return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
521 resinfo = FindResourceA(module, resource, (LPCSTR)RT_BITMAP);
523 FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
526 return D3DXERR_INVALIDDATA;
529 HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, LPCWSTR resource, D3DXIMAGE_INFO *info)
533 TRACE("(%p, %s, %p)\n", module, debugstr_w(resource), info);
535 resinfo = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA);
541 hr = load_resource_into_memory(module, resinfo, &buffer, &size);
542 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
543 return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
546 resinfo = FindResourceW(module, resource, (LPCWSTR)RT_BITMAP);
548 FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
551 return D3DXERR_INVALIDDATA;
554 /************************************************************
555 * D3DXLoadSurfaceFromFileInMemory
557 * Loads data from a given buffer into a surface and fills a given
558 * D3DXIMAGE_INFO structure with info about the source data.
561 * pDestSurface [I] pointer to the surface
562 * pDestPalette [I] palette to use
563 * pDestRect [I] to be filled area of the surface
564 * pSrcData [I] pointer to the source data
565 * SrcDataSize [I] size of the source data in bytes
566 * pSrcRect [I] area of the source data to load
567 * dwFilter [I] filter to apply on stretching
568 * Colorkey [I] colorkey
569 * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure
573 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcData or SrcDataSize are NULL
574 * D3DXERR_INVALIDDATA, if pSrcData is no valid image file
577 HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(LPDIRECT3DSURFACE9 pDestSurface,
578 CONST PALETTEENTRY *pDestPalette,
579 CONST RECT *pDestRect,
582 CONST RECT *pSrcRect,
585 D3DXIMAGE_INFO *pSrcInfo)
587 D3DXIMAGE_INFO imginfo;
590 IWICImagingFactory *factory;
591 IWICBitmapDecoder *decoder;
592 IWICBitmapFrameDecode *bitmapframe;
595 const PixelFormatDesc *formatdesc;
599 TRACE("(%p, %p, %p, %p, %d, %p, %d, %x, %p)\n", pDestSurface, pDestPalette, pDestRect, pSrcData,
600 SrcDataSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
602 if (!pDestSurface || !pSrcData || !SrcDataSize)
603 return D3DERR_INVALIDCALL;
605 hr = D3DXGetImageInfoFromFileInMemory(pSrcData, SrcDataSize, &imginfo);
610 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
612 if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory)))
615 if (FAILED(IWICImagingFactory_CreateStream(factory, &stream)))
617 IWICImagingFactory_Release(factory);
621 IWICStream_InitializeFromMemory(stream, (BYTE*)pSrcData, SrcDataSize);
623 hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
625 IStream_Release(stream);
626 IWICImagingFactory_Release(factory);
631 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &bitmapframe);
638 wicrect.X = pSrcRect->left;
639 wicrect.Y = pSrcRect->top;
640 wicrect.Width = pSrcRect->right - pSrcRect->left;
641 wicrect.Height = pSrcRect->bottom - pSrcRect->top;
647 wicrect.Width = imginfo.Width;
648 wicrect.Height = imginfo.Height;
651 SetRect(&rect, 0, 0, wicrect.Width, wicrect.Height);
653 formatdesc = get_format_info(imginfo.Format);
655 if (formatdesc->format == D3DFMT_UNKNOWN)
657 FIXME("Unsupported pixel format\n");
658 hr = D3DXERR_INVALIDDATA;
665 pitch = formatdesc->bytes_per_pixel * wicrect.Width;
666 buffer = HeapAlloc(GetProcessHeap(), 0, pitch * wicrect.Height);
668 hr = IWICBitmapFrameDecode_CopyPixels(bitmapframe, &wicrect, pitch,
669 pitch * wicrect.Height, buffer);
673 hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
674 buffer, imginfo.Format, pitch,
675 NULL, &rect, dwFilter, Colorkey);
678 HeapFree(GetProcessHeap(), 0, buffer);
681 IWICBitmapFrameDecode_Release(bitmapframe);
684 IWICBitmapDecoder_Release(decoder);
690 return D3DXERR_INVALIDDATA;
698 /************************************************************
699 * D3DXLoadSurfaceFromFile
701 HRESULT WINAPI D3DXLoadSurfaceFromFileA(LPDIRECT3DSURFACE9 pDestSurface,
702 CONST PALETTEENTRY *pDestPalette,
703 CONST RECT *pDestRect,
705 CONST RECT *pSrcRect,
708 D3DXIMAGE_INFO *pSrcInfo)
714 TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_a(pSrcFile),
715 pSrcRect, dwFilter, Colorkey, pSrcInfo);
717 if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
719 strlength = MultiByteToWideChar(CP_ACP, 0, pSrcFile, -1, NULL, 0);
720 pWidename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlength * sizeof(WCHAR));
721 MultiByteToWideChar(CP_ACP, 0, pSrcFile, -1, pWidename, strlength);
723 hr = D3DXLoadSurfaceFromFileW(pDestSurface, pDestPalette, pDestRect, pWidename, pSrcRect, dwFilter, Colorkey, pSrcInfo);
724 HeapFree(GetProcessHeap(), 0, pWidename);
729 HRESULT WINAPI D3DXLoadSurfaceFromFileW(LPDIRECT3DSURFACE9 pDestSurface,
730 CONST PALETTEENTRY *pDestPalette,
731 CONST RECT *pDestRect,
733 CONST RECT *pSrcRect,
736 D3DXIMAGE_INFO *pSrcInfo)
742 TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_w(pSrcFile),
743 pSrcRect, Filter, Colorkey, pSrcInfo);
745 if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
747 hr = map_view_of_file(pSrcFile, &pBuffer, &dwSize);
748 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
750 hr = D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, Filter, Colorkey, pSrcInfo);
751 UnmapViewOfFile(pBuffer);
756 /************************************************************
757 * D3DXLoadSurfaceFromResource
759 HRESULT WINAPI D3DXLoadSurfaceFromResourceA(LPDIRECT3DSURFACE9 pDestSurface,
760 CONST PALETTEENTRY *pDestPalette,
761 CONST RECT *pDestRect,
764 CONST RECT *pSrcRect,
767 D3DXIMAGE_INFO *pSrcInfo)
771 TRACE("(%p, %p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, hSrcModule,
772 debugstr_a(pResource), pSrcRect, dwFilter, Colorkey, pSrcInfo);
774 if( !pDestSurface ) return D3DERR_INVALIDCALL;
776 hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_RCDATA);
782 hr = load_resource_into_memory(hSrcModule, hResInfo, &pBuffer, &dwSize);
783 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
784 return D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
787 hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_BITMAP);
789 FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
792 return D3DXERR_INVALIDDATA;
795 HRESULT WINAPI D3DXLoadSurfaceFromResourceW(LPDIRECT3DSURFACE9 pDestSurface,
796 CONST PALETTEENTRY *pDestPalette,
797 CONST RECT *pDestRect,
800 CONST RECT *pSrcRect,
803 D3DXIMAGE_INFO *pSrcInfo)
807 TRACE("(%p, %p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, hSrcModule,
808 debugstr_w(pResource), pSrcRect, dwFilter, Colorkey, pSrcInfo);
810 if( !pDestSurface ) return D3DERR_INVALIDCALL;
812 hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_RCDATA);
818 hr = load_resource_into_memory(hSrcModule, hResInfo, &pBuffer, &dwSize);
819 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
820 return D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
823 hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_BITMAP);
825 FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
828 return D3DXERR_INVALIDDATA;
832 /************************************************************
833 * helper functions for D3DXLoadSurfaceFromMemory
835 struct argb_conversion_info
837 CONST PixelFormatDesc *srcformat;
838 CONST PixelFormatDesc *destformat;
839 DWORD srcshift[4], destshift[4];
840 DWORD srcmask[4], destmask[4];
841 BOOL process_channel[4];
845 static void init_argb_conversion_info(CONST PixelFormatDesc *srcformat, CONST PixelFormatDesc *destformat, struct argb_conversion_info *info)
848 ZeroMemory(info->process_channel, 4 * sizeof(BOOL));
849 info->channelmask = 0;
851 info->srcformat = srcformat;
852 info->destformat = destformat;
854 for(i = 0;i < 4;i++) {
855 /* srcshift is used to extract the _relevant_ components */
856 info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0);
858 /* destshift is used to move the components to the correct position */
859 info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0);
861 info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i];
862 info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i];
864 /* channelmask specifies bits which aren't used in the source format but in the destination one */
865 if(destformat->bits[i]) {
866 if(srcformat->bits[i]) info->process_channel[i] = TRUE;
867 else info->channelmask |= info->destmask[i];
872 static DWORD dword_from_bytes(CONST BYTE *src, UINT bytes_per_pixel)
875 static BOOL fixme_once;
877 if(bytes_per_pixel > sizeof(DWORD)) {
878 if(!fixme_once++) FIXME("Unsupported image: %u bytes per pixel\n", bytes_per_pixel);
879 bytes_per_pixel = sizeof(DWORD);
882 memcpy(&ret, src, bytes_per_pixel);
886 static void dword_to_bytes(BYTE *dst, DWORD dword, UINT bytes_per_pixel)
888 static BOOL fixme_once;
890 if(bytes_per_pixel > sizeof(DWORD)) {
891 if(!fixme_once++) FIXME("Unsupported image: %u bytes per pixel\n", bytes_per_pixel);
892 ZeroMemory(dst, bytes_per_pixel);
893 bytes_per_pixel = sizeof(DWORD);
896 memcpy(dst, &dword, bytes_per_pixel);
899 /************************************************************
900 * get_relevant_argb_components
902 * Extracts the relevant components from the source color and
903 * drops the less significant bits if they aren't used by the destination format.
905 static void get_relevant_argb_components(CONST struct argb_conversion_info *info, CONST DWORD col, DWORD *out)
909 if(info->process_channel[i])
910 out[i] = (col & info->srcmask[i]) >> info->srcshift[i];
913 /************************************************************
916 * Recombines the output of get_relevant_argb_components and converts
917 * it to the destination format.
919 static DWORD make_argb_color(CONST struct argb_conversion_info *info, CONST DWORD *in)
924 for(i = 0;i < 4;i++) {
925 if(info->process_channel[i]) {
926 /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */
928 for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift;
929 val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i];
932 val |= info->channelmask; /* new channels are set to their maximal value */
936 static void format_to_vec4(const PixelFormatDesc *format, const DWORD *src, struct vec4 *dst)
942 mask = (1 << format->bits[1]) - 1;
943 dst->x = (float)((*src >> format->shift[1]) & mask) / mask;
950 mask = (1 << format->bits[2]) - 1;
951 dst->y = (float)((*src >> format->shift[2]) & mask) / mask;
958 mask = (1 << format->bits[3]) - 1;
959 dst->z = (float)((*src >> format->shift[3]) & mask) / mask;
966 mask = (1 << format->bits[0]) - 1;
967 dst->w = (float)((*src >> format->shift[0]) & mask) / mask;
973 static void format_from_vec4(const PixelFormatDesc *format, const struct vec4 *src, DWORD *dst)
978 *dst |= (DWORD)(src->x * ((1 << format->bits[1]) - 1) + 0.5f) << format->shift[1];
980 *dst |= (DWORD)(src->y * ((1 << format->bits[2]) - 1) + 0.5f) << format->shift[2];
982 *dst |= (DWORD)(src->z * ((1 << format->bits[3]) - 1) + 0.5f) << format->shift[3];
984 *dst |= (DWORD)(src->w * ((1 << format->bits[0]) - 1) + 0.5f) << format->shift[0];
987 /************************************************************
990 * Copies the source buffer to the destination buffer, performing
991 * any necessary format conversion and color keying.
992 * Pixels outsize the source rect are blacked out.
993 * Works only for ARGB formats with 1 - 4 bytes per pixel.
995 static void copy_simple_data(const BYTE *src, UINT srcpitch, SIZE src_size, const PixelFormatDesc *srcformat,
996 BYTE *dest, UINT destpitch, SIZE dst_size, const PixelFormatDesc *destformat, D3DCOLOR colorkey)
998 struct argb_conversion_info conv_info, ck_conv_info;
999 const PixelFormatDesc *ck_format = NULL;
1000 DWORD channels[4], pixel;
1001 UINT minwidth, minheight;
1004 ZeroMemory(channels, sizeof(channels));
1005 init_argb_conversion_info(srcformat, destformat, &conv_info);
1007 minwidth = (src_size.cx < dst_size.cx) ? src_size.cx : dst_size.cx;
1008 minheight = (src_size.cy < dst_size.cy) ? src_size.cy : dst_size.cy;
1012 /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */
1013 ck_format = get_format_info(D3DFMT_A8R8G8B8);
1014 init_argb_conversion_info(srcformat, ck_format, &ck_conv_info);
1017 for(y = 0;y < minheight;y++) {
1018 const BYTE *srcptr = src + y * srcpitch;
1019 BYTE *destptr = dest + y * destpitch;
1022 for(x = 0;x < minwidth;x++) {
1023 /* extract source color components */
1024 pixel = dword_from_bytes(srcptr, srcformat->bytes_per_pixel);
1026 if (!srcformat->to_rgba && !destformat->from_rgba)
1028 get_relevant_argb_components(&conv_info, pixel, channels);
1029 val = make_argb_color(&conv_info, channels);
1033 get_relevant_argb_components(&ck_conv_info, pixel, channels);
1034 pixel = make_argb_color(&ck_conv_info, channels);
1035 if (pixel == colorkey)
1036 val &= ~conv_info.destmask[0];
1041 struct vec4 color, tmp;
1043 format_to_vec4(srcformat, &pixel, &color);
1044 if (srcformat->to_rgba)
1045 srcformat->to_rgba(&color, &tmp);
1051 format_from_vec4(ck_format, &tmp, &pixel);
1052 if (pixel == colorkey)
1056 if (destformat->from_rgba)
1057 destformat->from_rgba(&tmp, &color);
1061 format_from_vec4(destformat, &color, &val);
1064 dword_to_bytes(destptr, val, destformat->bytes_per_pixel);
1065 srcptr += srcformat->bytes_per_pixel;
1066 destptr += destformat->bytes_per_pixel;
1069 if (src_size.cx < dst_size.cx) /* black out remaining pixels */
1070 memset(destptr, 0, destformat->bytes_per_pixel * (dst_size.cx - src_size.cx));
1072 if (src_size.cy < dst_size.cy) /* black out remaining pixels */
1073 memset(dest + src_size.cy * destpitch, 0, destpitch * (dst_size.cy - src_size.cy));
1076 /************************************************************
1077 * point_filter_simple_data
1079 * Copies the source buffer to the destination buffer, performing
1080 * any necessary format conversion, color keying and stretching
1081 * using a point filter.
1082 * Works only for ARGB formats with 1 - 4 bytes per pixel.
1084 static void point_filter_simple_data(const BYTE *src, UINT srcpitch, SIZE src_size, const PixelFormatDesc *srcformat,
1085 BYTE *dest, UINT destpitch, SIZE dst_size, const PixelFormatDesc *destformat, D3DCOLOR colorkey)
1087 struct argb_conversion_info conv_info, ck_conv_info;
1088 const PixelFormatDesc *ck_format = NULL;
1089 DWORD channels[4], pixel;
1093 ZeroMemory(channels, sizeof(channels));
1094 init_argb_conversion_info(srcformat, destformat, &conv_info);
1098 /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */
1099 ck_format = get_format_info(D3DFMT_A8R8G8B8);
1100 init_argb_conversion_info(srcformat, ck_format, &ck_conv_info);
1103 for (y = 0; y < dst_size.cy; ++y)
1105 BYTE *destptr = dest + y * destpitch;
1106 const BYTE *bufptr = src + srcpitch * (y * src_size.cy / dst_size.cy);
1108 for (x = 0; x < dst_size.cx; ++x)
1110 const BYTE *srcptr = bufptr + (x * src_size.cx / dst_size.cx) * srcformat->bytes_per_pixel;
1113 /* extract source color components */
1114 pixel = dword_from_bytes(srcptr, srcformat->bytes_per_pixel);
1116 if (!srcformat->to_rgba && !destformat->from_rgba)
1118 get_relevant_argb_components(&conv_info, pixel, channels);
1119 val = make_argb_color(&conv_info, channels);
1123 get_relevant_argb_components(&ck_conv_info, pixel, channels);
1124 pixel = make_argb_color(&ck_conv_info, channels);
1125 if (pixel == colorkey)
1126 val &= ~conv_info.destmask[0];
1131 struct vec4 color, tmp;
1133 format_to_vec4(srcformat, &pixel, &color);
1134 if (srcformat->to_rgba)
1135 srcformat->to_rgba(&color, &tmp);
1141 format_from_vec4(ck_format, &tmp, &pixel);
1142 if (pixel == colorkey)
1146 if (destformat->from_rgba)
1147 destformat->from_rgba(&tmp, &color);
1151 format_from_vec4(destformat, &color, &val);
1154 dword_to_bytes(destptr, val, destformat->bytes_per_pixel);
1155 destptr += destformat->bytes_per_pixel;
1160 /************************************************************
1161 * D3DXLoadSurfaceFromMemory
1163 * Loads data from a given memory chunk into a surface,
1164 * applying any of the specified filters.
1167 * pDestSurface [I] pointer to the surface
1168 * pDestPalette [I] palette to use
1169 * pDestRect [I] to be filled area of the surface
1170 * pSrcMemory [I] pointer to the source data
1171 * SrcFormat [I] format of the source pixel data
1172 * SrcPitch [I] number of bytes in a row
1173 * pSrcPalette [I] palette used in the source image
1174 * pSrcRect [I] area of the source data to load
1175 * dwFilter [I] filter to apply on stretching
1176 * Colorkey [I] colorkey
1179 * Success: D3D_OK, if we successfully load the pixel data into our surface or
1180 * if pSrcMemory is NULL but the other parameters are valid
1181 * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or
1182 * if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or
1183 * if DestRect is invalid
1184 * D3DXERR_INVALIDDATA, if we fail to lock pDestSurface
1185 * E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid
1188 * pSrcRect specifies the dimensions of the source data;
1189 * negative values for pSrcRect are allowed as we're only looking at the width and height anyway.
1192 HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface,
1193 const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory,
1194 D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect,
1195 DWORD filter, D3DCOLOR color_key)
1197 CONST PixelFormatDesc *srcformatdesc, *destformatdesc;
1198 D3DSURFACE_DESC surfdesc;
1199 D3DLOCKED_RECT lockrect;
1200 SIZE src_size, dst_size;
1203 TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s %#x, 0x%08x)\n",
1204 dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_memory, src_format,
1205 src_pitch, src_palette, wine_dbgstr_rect(src_rect), filter, color_key);
1207 if (!dst_surface || !src_memory || !src_rect)
1208 return D3DERR_INVALIDCALL;
1209 if (src_format == D3DFMT_UNKNOWN
1210 || src_rect->left >= src_rect->right
1211 || src_rect->top >= src_rect->bottom)
1214 if (filter == D3DX_DEFAULT)
1215 filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
1217 IDirect3DSurface9_GetDesc(dst_surface, &surfdesc);
1219 src_size.cx = src_rect->right - src_rect->left;
1220 src_size.cy = src_rect->bottom - src_rect->top;
1223 dst_size.cx = surfdesc.Width;
1224 dst_size.cy = surfdesc.Height;
1228 if (dst_rect->left > dst_rect->right || dst_rect->right > surfdesc.Width)
1229 return D3DERR_INVALIDCALL;
1230 if (dst_rect->top > dst_rect->bottom || dst_rect->bottom > surfdesc.Height)
1231 return D3DERR_INVALIDCALL;
1232 if (dst_rect->left < 0 || dst_rect->top < 0)
1233 return D3DERR_INVALIDCALL;
1234 dst_size.cx = dst_rect->right - dst_rect->left;
1235 dst_size.cy = dst_rect->bottom - dst_rect->top;
1236 if (!dst_size.cx || !dst_size.cy)
1240 srcformatdesc = get_format_info(src_format);
1241 if (srcformatdesc->type == FORMAT_UNKNOWN)
1244 destformatdesc = get_format_info(surfdesc.Format);
1245 if (destformatdesc->type == FORMAT_UNKNOWN)
1248 if (src_format == surfdesc.Format
1249 && dst_size.cx == src_size.cx
1250 && dst_size.cy == src_size.cy) /* Simple copy. */
1252 UINT row_block_count = ((src_size.cx + srcformatdesc->block_width - 1) / srcformatdesc->block_width);
1253 UINT row_count = (src_size.cy + srcformatdesc->block_height - 1) / srcformatdesc->block_height;
1254 const BYTE *src_addr;
1258 if (src_rect->left & (srcformatdesc->block_width - 1)
1259 || src_rect->top & (srcformatdesc->block_height - 1)
1260 || (src_rect->right & (srcformatdesc->block_width - 1)
1261 && src_size.cx != surfdesc.Width)
1262 || (src_rect->bottom & (srcformatdesc->block_height - 1)
1263 && src_size.cy != surfdesc.Height))
1265 WARN("Source rect %s is misaligned.\n", wine_dbgstr_rect(src_rect));
1266 return D3DXERR_INVALIDDATA;
1269 if (FAILED(hr = IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
1270 return D3DXERR_INVALIDDATA;
1272 src_addr = src_memory;
1273 src_addr += (src_rect->top / srcformatdesc->block_height) * src_pitch;
1274 src_addr += (src_rect->left / srcformatdesc->block_width) * srcformatdesc->block_byte_count;
1275 dst_addr = lockrect.pBits;
1277 for (row = 0; row < row_count; ++row)
1279 memcpy(dst_addr, src_addr, row_block_count * srcformatdesc->block_byte_count);
1280 src_addr += src_pitch;
1281 dst_addr += lockrect.Pitch;
1284 IDirect3DSurface9_UnlockRect(dst_surface);
1286 else /* Stretching or format conversion. */
1288 if (srcformatdesc->bytes_per_pixel > 4)
1290 if (destformatdesc->bytes_per_pixel > 4)
1292 if (srcformatdesc->block_height != 1 || srcformatdesc->block_width != 1)
1294 if (destformatdesc->block_height != 1 || destformatdesc->block_width != 1)
1297 if (FAILED(hr = IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
1298 return D3DXERR_INVALIDDATA;
1300 if ((filter & 0xf) == D3DX_FILTER_NONE)
1302 copy_simple_data(src_memory, src_pitch, src_size, srcformatdesc,
1303 lockrect.pBits, lockrect.Pitch, dst_size, destformatdesc, color_key);
1305 else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */
1307 if ((filter & 0xf) != D3DX_FILTER_POINT)
1308 FIXME("Unhandled filter %#x.\n", filter);
1310 /* Always apply a point filter until D3DX_FILTER_LINEAR,
1311 * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */
1312 point_filter_simple_data(src_memory, src_pitch, src_size, srcformatdesc,
1313 lockrect.pBits, lockrect.Pitch, dst_size, destformatdesc, color_key);
1316 IDirect3DSurface9_UnlockRect(dst_surface);
1322 /************************************************************
1323 * D3DXLoadSurfaceFromSurface
1325 * Copies the contents from one surface to another, performing any required
1326 * format conversion, resizing or filtering.
1329 * pDestSurface [I] pointer to the destination surface
1330 * pDestPalette [I] palette to use
1331 * pDestRect [I] to be filled area of the surface
1332 * pSrcSurface [I] pointer to the source surface
1333 * pSrcPalette [I] palette used for the source surface
1334 * pSrcRect [I] area of the source data to load
1335 * dwFilter [I] filter to apply on resizing
1336 * Colorkey [I] any ARGB value or 0 to disable color-keying
1340 * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
1341 * D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
1344 HRESULT WINAPI D3DXLoadSurfaceFromSurface(LPDIRECT3DSURFACE9 pDestSurface,
1345 CONST PALETTEENTRY *pDestPalette,
1346 CONST RECT *pDestRect,
1347 LPDIRECT3DSURFACE9 pSrcSurface,
1348 CONST PALETTEENTRY *pSrcPalette,
1349 CONST RECT *pSrcRect,
1354 D3DLOCKED_RECT lock;
1355 D3DSURFACE_DESC SrcDesc;
1358 TRACE("(%p, %p, %p, %p, %p, %p, %u, %#x): relay\n", pDestSurface, pDestPalette, pDestRect,
1359 pSrcSurface, pSrcPalette, pSrcRect, dwFilter, Colorkey);
1361 if( !pDestSurface || !pSrcSurface ) return D3DERR_INVALIDCALL;
1363 IDirect3DSurface9_GetDesc(pSrcSurface, &SrcDesc);
1365 if( !pSrcRect ) SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height);
1366 else rect = *pSrcRect;
1368 hr = IDirect3DSurface9_LockRect(pSrcSurface, &lock, NULL, D3DLOCK_READONLY);
1369 if(FAILED(hr)) return D3DXERR_INVALIDDATA;
1371 hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
1372 lock.pBits, SrcDesc.Format, lock.Pitch,
1373 pSrcPalette, &rect, dwFilter, Colorkey);
1375 IDirect3DSurface9_UnlockRect(pSrcSurface);
1380 HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1381 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1387 TRACE("(%s, %#x, %p, %p, %s): relay\n",
1388 wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
1390 if (!dst_filename) return D3DERR_INVALIDCALL;
1392 len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0);
1393 filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1394 if (!filename) return E_OUTOFMEMORY;
1395 MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len);
1397 hr = D3DXSaveSurfaceToFileW(filename, file_format, src_surface, src_palette, src_rect);
1399 HeapFree(GetProcessHeap(), 0, filename);
1403 HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1404 IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1406 IWICImagingFactory *factory;
1407 IWICBitmapEncoder *encoder = NULL;
1408 IWICBitmapFrameEncode *frame = NULL;
1409 IPropertyBag2 *encoder_options = NULL;
1410 IWICStream *stream = NULL;
1413 const CLSID *encoder_clsid;
1414 const GUID *pixel_format_guid;
1415 WICPixelFormatGUID wic_pixel_format;
1416 D3DFORMAT d3d_pixel_format;
1417 D3DSURFACE_DESC src_surface_desc;
1418 D3DLOCKED_RECT locked_rect;
1421 TRACE("(%s, %#x, %p, %p, %s)\n",
1422 wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
1424 if (!dst_filename || !src_surface) return D3DERR_INVALIDCALL;
1428 FIXME("Saving surfaces with palettized pixel formats not implemented yet\n");
1429 return D3DERR_INVALIDCALL;
1432 switch (file_format)
1435 encoder_clsid = &CLSID_WICBmpEncoder;
1438 encoder_clsid = &CLSID_WICPngEncoder;
1441 encoder_clsid = &CLSID_WICJpegEncoder;
1449 FIXME("File format %#x is not supported yet\n", file_format);
1452 return D3DERR_INVALIDCALL;
1455 IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc);
1458 if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom)
1460 if (src_rect->left < 0 || src_rect->top < 0)
1461 return D3DERR_INVALIDCALL;
1462 if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom)
1463 return D3DERR_INVALIDCALL;
1464 if (src_rect->right > src_surface_desc.Width || src_rect->bottom > src_surface_desc.Height)
1465 return D3DERR_INVALIDCALL;
1467 width = src_rect->right - src_rect->left;
1468 height = src_rect->bottom - src_rect->top;
1472 width = src_surface_desc.Width;
1473 height = src_surface_desc.Height;
1476 initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1478 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1479 &IID_IWICImagingFactory, (void **)&factory);
1480 if (FAILED(hr)) goto cleanup_err;
1482 hr = IWICImagingFactory_CreateStream(factory, &stream);
1483 IWICImagingFactory_Release(factory);
1484 if (FAILED(hr)) goto cleanup_err;
1486 hr = IWICStream_InitializeFromFilename(stream, dst_filename, GENERIC_WRITE);
1487 if (FAILED(hr)) goto cleanup_err;
1489 hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1490 &IID_IWICBitmapEncoder, (void **)&encoder);
1491 if (FAILED(hr)) goto cleanup_err;
1493 hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)stream, WICBitmapEncoderNoCache);
1494 IStream_Release((IStream *)stream);
1496 if (FAILED(hr)) goto cleanup_err;
1498 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options);
1499 if (FAILED(hr)) goto cleanup_err;
1501 hr = IWICBitmapFrameEncode_Initialize(frame, encoder_options);
1502 if (FAILED(hr)) goto cleanup_err;
1504 hr = IWICBitmapFrameEncode_SetSize(frame, width, height);
1505 if (FAILED(hr)) goto cleanup_err;
1507 pixel_format_guid = d3dformat_to_wic_guid(src_surface_desc.Format);
1508 if (!pixel_format_guid)
1510 FIXME("Pixel format %#x is not supported yet\n", src_surface_desc.Format);
1515 memcpy(&wic_pixel_format, pixel_format_guid, sizeof(GUID));
1516 hr = IWICBitmapFrameEncode_SetPixelFormat(frame, &wic_pixel_format);
1517 d3d_pixel_format = wic_guid_to_d3dformat(&wic_pixel_format);
1518 if (SUCCEEDED(hr) && d3d_pixel_format != D3DFMT_UNKNOWN)
1520 TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format), d3d_pixel_format);
1522 if (src_surface_desc.Format == d3d_pixel_format) /* Simple copy */
1524 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY);
1527 IWICBitmapFrameEncode_WritePixels(frame, height,
1528 locked_rect.Pitch, height * locked_rect.Pitch, locked_rect.pBits);
1529 IDirect3DSurface9_UnlockRect(src_surface);
1532 else /* Pixel format conversion */
1534 const PixelFormatDesc *src_format_desc, *dst_format_desc;
1539 src_format_desc = get_format_info(src_surface_desc.Format);
1540 dst_format_desc = get_format_info(d3d_pixel_format);
1541 if (src_format_desc->format == D3DFMT_UNKNOWN || dst_format_desc->format == D3DFMT_UNKNOWN)
1543 FIXME("Unsupported pixel format conversion %#x -> %#x\n",
1544 src_surface_desc.Format, d3d_pixel_format);
1549 if (src_format_desc->bytes_per_pixel > 4
1550 || dst_format_desc->bytes_per_pixel > 4
1551 || src_format_desc->block_height != 1 || src_format_desc->block_width != 1
1552 || dst_format_desc->block_height != 1 || dst_format_desc->block_width != 1)
1560 dst_pitch = width * dst_format_desc->bytes_per_pixel;
1561 dst_data = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height);
1568 hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY);
1571 copy_simple_data(locked_rect.pBits, locked_rect.Pitch, size, src_format_desc,
1572 dst_data, dst_pitch, size, dst_format_desc, 0);
1573 IDirect3DSurface9_UnlockRect(src_surface);
1576 IWICBitmapFrameEncode_WritePixels(frame, height, dst_pitch, dst_pitch * height, dst_data);
1577 HeapFree(GetProcessHeap(), 0, dst_data);
1580 hr = IWICBitmapFrameEncode_Commit(frame);
1581 if (SUCCEEDED(hr)) hr = IWICBitmapEncoder_Commit(encoder);
1583 else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format);
1586 if (FAILED(hr)) hr = D3DERR_INVALIDCALL;
1589 if (stream) IStream_Release((IStream *)stream);
1591 if (frame) IWICBitmapFrameEncode_Release(frame);
1592 if (encoder_options) IPropertyBag2_Release(encoder_options);
1594 if (encoder) IWICBitmapEncoder_Release(encoder);
1596 if (SUCCEEDED(initresult)) CoUninitialize();