strmbase: do not lock in BaseOutputPinImpl_GetDeliveryBuffer the MemInputPin will...
[wine] / dlls / 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 "wine/debug.h"
22 #include "wine/unicode.h"
23 #include "d3dx9_36_private.h"
24
25 #include "initguid.h"
26 #include "wincodec.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
29
30
31 /* Wine-specific WIC GUIDs */
32 DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22);
33
34 static const struct
35 {
36     const GUID *wic_guid;
37     D3DFORMAT d3dformat;
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 }
47 };
48
49 static D3DFORMAT wic_guid_to_d3dformat(const GUID *guid)
50 {
51     int i;
52
53     for (i = 0; i < sizeof(wic_pixel_formats) / sizeof(wic_pixel_formats[0]); i++)
54     {
55         if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid))
56             return wic_pixel_formats[i].d3dformat;
57     }
58
59     return D3DFMT_UNKNOWN;
60 }
61
62 static const GUID *d3dformat_to_wic_guid(D3DFORMAT format)
63 {
64     int i;
65
66     for (i = 0; i < sizeof(wic_pixel_formats) / sizeof(wic_pixel_formats[0]); i++)
67     {
68         if (wic_pixel_formats[i].d3dformat == format)
69             return wic_pixel_formats[i].wic_guid;
70     }
71
72     return NULL;
73 }
74
75 /* dds_header.flags */
76 #define DDS_CAPS 0x1
77 #define DDS_HEIGHT 0x2
78 #define DDS_WIDTH 0x2
79 #define DDS_PITCH 0x8
80 #define DDS_PIXELFORMAT 0x1000
81 #define DDS_MIPMAPCOUNT 0x20000
82 #define DDS_LINEARSIZE 0x80000
83 #define DDS_DEPTH 0x800000
84
85 /* dds_header.caps */
86 #define DDS_CAPS_COMPLEX 0x8
87 #define DDS_CAPS_TEXTURE 0x1000
88 #define DDS_CAPS_MIPMAP 0x400000
89
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
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
108 struct dds_pixel_format
109 {
110     DWORD size;
111     DWORD flags;
112     DWORD fourcc;
113     DWORD bpp;
114     DWORD rmask;
115     DWORD gmask;
116     DWORD bmask;
117     DWORD amask;
118 };
119
120 struct dds_header
121 {
122     DWORD signature;
123     DWORD size;
124     DWORD flags;
125     DWORD height;
126     DWORD width;
127     DWORD pitch_or_linear_size;
128     DWORD depth;
129     DWORD miplevels;
130     DWORD reserved[11];
131     struct dds_pixel_format pixel_format;
132     DWORD caps;
133     DWORD caps2;
134     DWORD caps3;
135     DWORD caps4;
136     DWORD reserved2;
137 };
138
139 static D3DFORMAT dds_fourcc_to_d3dformat(DWORD fourcc)
140 {
141     int i;
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')
152     };
153
154     for (i = 0; i < sizeof(known_fourcc) / sizeof(known_fourcc[0]); i++)
155     {
156         if (known_fourcc[i] == fourcc)
157             return fourcc;
158     }
159
160     WARN("Unknown FourCC %#x\n", fourcc);
161     return D3DFMT_UNKNOWN;
162 }
163
164 static D3DFORMAT dds_rgb_to_d3dformat(const struct dds_pixel_format *pixel_format)
165 {
166     int i;
167     static const struct {
168         DWORD bpp;
169         DWORD rmask;
170         DWORD gmask;
171         DWORD bmask;
172         DWORD amask;
173         D3DFORMAT format;
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 },
188     };
189
190     for (i = 0; i < sizeof(rgb_pixel_formats) / sizeof(rgb_pixel_formats[0]); i++)
191     {
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)
196         {
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;
201         }
202     }
203
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;
207 }
208
209 static D3DFORMAT dds_luminance_to_d3dformat(const struct dds_pixel_format *pixel_format)
210 {
211     if (pixel_format->bpp == 8)
212     {
213         if (pixel_format->rmask == 0xff)
214             return D3DFMT_L8;
215         if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x0f && pixel_format->amask == 0xf0)
216             return D3DFMT_A4L4;
217     }
218     if (pixel_format->bpp == 16)
219     {
220         if ((pixel_format->flags & DDS_PF_ALPHA) && pixel_format->rmask == 0x00ff && pixel_format->amask == 0xff00)
221             return D3DFMT_A8L8;
222     }
223
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;
227 }
228
229 static D3DFORMAT dds_alpha_to_d3dformat(const struct dds_pixel_format *pixel_format)
230 {
231     if (pixel_format->bpp == 8 && pixel_format->amask == 0xff)
232         return D3DFMT_A8;
233
234     WARN("Unknown Alpha pixel format (%#x, %#x)\n", pixel_format->bpp, pixel_format->rmask);
235     return D3DFMT_UNKNOWN;
236 }
237
238 static D3DFORMAT dds_pixel_format_to_d3dformat(const struct dds_pixel_format *pixel_format)
239 {
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);
248
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;
253 }
254
255 /************************************************************
256 * get_image_info_from_dds
257 *
258 * Fills a D3DXIMAGE_INFO structure with information
259 * about a DDS file stored in the memory.
260 *
261 * PARAMS
262 *   buffer  [I] pointer to DDS data
263 *   length  [I] size of DDS data
264 *   info    [O] pointer to D3DXIMAGE_INFO structure
265 *
266 * RETURNS
267 *   Success: D3D_OK
268 *   Failure: D3DXERR_INVALIDDATA
269 *
270 */
271 static HRESULT get_image_info_from_dds(const void *buffer, DWORD length, D3DXIMAGE_INFO *info)
272 {
273    const struct dds_header *header = buffer;
274
275    if (length < sizeof(*header) || !info)
276        return D3DXERR_INVALIDDATA;
277
278    if (header->pixel_format.size != sizeof(header->pixel_format))
279        return D3DXERR_INVALIDDATA;
280
281    info->Width = header->width;
282    info->Height = header->height;
283    info->Depth = 1;
284    info->MipLevels = (header->flags & DDS_MIPMAPCOUNT) ?  header->miplevels : 1;
285
286    info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format);
287    if (info->Format == D3DFMT_UNKNOWN)
288        return D3DXERR_INVALIDDATA;
289
290    if (header->caps2 & DDS_CAPS2_VOLUME)
291    {
292        info->Depth = header->depth;
293        info->ResourceType = D3DRTYPE_VOLUMETEXTURE;
294    }
295    else if (header->caps2 & DDS_CAPS2_CUBEMAP)
296    {
297        info->ResourceType = D3DRTYPE_CUBETEXTURE;
298    }
299    else
300    {
301        info->ResourceType = D3DRTYPE_TEXTURE;
302    }
303
304    info->ImageFileFormat = D3DXIFF_DDS;
305
306    return D3D_OK;
307 }
308
309 /************************************************************
310  * D3DXGetImageInfoFromFileInMemory
311  *
312  * Fills a D3DXIMAGE_INFO structure with info about an image
313  *
314  * PARAMS
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
318  *
319  * RETURNS
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
324  *                                if datasize is 0
325  *
326  * NOTES
327  *   datasize may be bigger than the actual file size
328  *
329  */
330 HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(LPCVOID data, UINT datasize, D3DXIMAGE_INFO *info)
331 {
332     IWICImagingFactory *factory;
333     IWICBitmapDecoder *decoder = NULL;
334     IWICStream *stream;
335     HRESULT hr;
336     HRESULT initresult;
337
338     TRACE("(%p, %d, %p)\n", data, datasize, info);
339
340     if (!data || !datasize)
341         return D3DERR_INVALIDCALL;
342
343     if (!info)
344         return D3D_OK;
345
346     if ((datasize >= 4) && !strncmp(data, "DDS ", 4))
347         return get_image_info_from_dds(data, datasize, info);
348
349     initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
350
351     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory);
352
353     if (SUCCEEDED(hr)) {
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);
359     }
360
361     if (FAILED(hr)) {
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");
370     }
371
372     if (SUCCEEDED(hr)) {
373         GUID container_format;
374         UINT frame_count;
375
376         hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format);
377         if (SUCCEEDED(hr)) {
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;
390             } else {
391                 WARN("Unsupported image file format %s\n", debugstr_guid(&container_format));
392                 hr = D3DXERR_INVALIDDATA;
393             }
394         }
395
396         if (SUCCEEDED(hr))
397             hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
398         if (SUCCEEDED(hr) && !frame_count)
399             hr = D3DXERR_INVALIDDATA;
400
401         if (SUCCEEDED(hr)) {
402             IWICBitmapFrameDecode *frame = NULL;
403
404             hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
405
406             if (SUCCEEDED(hr))
407                 hr = IWICBitmapFrameDecode_GetSize(frame, &info->Width, &info->Height);
408
409             if (SUCCEEDED(hr)) {
410                 WICPixelFormatGUID pixel_format;
411
412                 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &pixel_format);
413                 if (SUCCEEDED(hr)) {
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;
418                     }
419                 }
420             }
421
422             if (frame)
423                  IWICBitmapFrameDecode_Release(frame);
424
425             info->Depth = 1;
426             info->MipLevels = 1;
427             info->ResourceType = D3DRTYPE_TEXTURE;
428         }
429     }
430
431     if (decoder)
432         IWICBitmapDecoder_Release(decoder);
433
434     if (SUCCEEDED(initresult))
435         CoUninitialize();
436
437     if (FAILED(hr)) {
438         TRACE("Invalid or unsupported image file\n");
439         return D3DXERR_INVALIDDATA;
440     }
441
442     return D3D_OK;
443 }
444
445 /************************************************************
446  * D3DXGetImageInfoFromFile
447  *
448  * RETURNS
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
454  *
455  */
456 HRESULT WINAPI D3DXGetImageInfoFromFileA(LPCSTR file, D3DXIMAGE_INFO *info)
457 {
458     LPWSTR widename;
459     HRESULT hr;
460     int strlength;
461
462     TRACE("(%s, %p): relay\n", debugstr_a(file), info);
463
464     if( !file ) return D3DERR_INVALIDCALL;
465
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);
469
470     hr = D3DXGetImageInfoFromFileW(widename, info);
471     HeapFree(GetProcessHeap(), 0, widename);
472
473     return hr;
474 }
475
476 HRESULT WINAPI D3DXGetImageInfoFromFileW(LPCWSTR file, D3DXIMAGE_INFO *info)
477 {
478     HRESULT hr;
479     DWORD size;
480     LPVOID buffer;
481
482     TRACE("(%s, %p): relay\n", debugstr_w(file), info);
483
484     if( !file ) return D3DERR_INVALIDCALL;
485
486     hr = map_view_of_file(file, &buffer, &size);
487     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
488
489     hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info);
490     UnmapViewOfFile(buffer);
491
492     return hr;
493 }
494
495 /************************************************************
496  * D3DXGetImageInfoFromResource
497  *
498  * RETURNS
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
502  *
503  */
504 HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, LPCSTR resource, D3DXIMAGE_INFO *info)
505 {
506     HRSRC resinfo;
507
508     TRACE("(%p, %s, %p)\n", module, debugstr_a(resource), info);
509
510     resinfo = FindResourceA(module, resource, (LPCSTR)RT_RCDATA);
511     if(resinfo) {
512         LPVOID buffer;
513         HRESULT hr;
514         DWORD size;
515
516         hr = load_resource_into_memory(module, resinfo, &buffer, &size);
517         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
518         return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
519     }
520
521     resinfo = FindResourceA(module, resource, (LPCSTR)RT_BITMAP);
522     if(resinfo) {
523         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
524         return E_NOTIMPL;
525     }
526     return D3DXERR_INVALIDDATA;
527 }
528
529 HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, LPCWSTR resource, D3DXIMAGE_INFO *info)
530 {
531     HRSRC resinfo;
532
533     TRACE("(%p, %s, %p)\n", module, debugstr_w(resource), info);
534
535     resinfo = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA);
536     if(resinfo) {
537         LPVOID buffer;
538         HRESULT hr;
539         DWORD size;
540
541         hr = load_resource_into_memory(module, resinfo, &buffer, &size);
542         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
543         return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
544     }
545
546     resinfo = FindResourceW(module, resource, (LPCWSTR)RT_BITMAP);
547     if(resinfo) {
548         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
549         return E_NOTIMPL;
550     }
551     return D3DXERR_INVALIDDATA;
552 }
553
554 /************************************************************
555  * D3DXLoadSurfaceFromFileInMemory
556  *
557  * Loads data from a given buffer into a surface and fills a given
558  * D3DXIMAGE_INFO structure with info about the source data.
559  *
560  * PARAMS
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
570  *
571  * RETURNS
572  *   Success: D3D_OK
573  *   Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcData or SrcDataSize are NULL
574  *            D3DXERR_INVALIDDATA, if pSrcData is no valid image file
575  *
576  */
577 HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(LPDIRECT3DSURFACE9 pDestSurface,
578                                                CONST PALETTEENTRY *pDestPalette,
579                                                CONST RECT *pDestRect,
580                                                LPCVOID pSrcData,
581                                                UINT SrcDataSize,
582                                                CONST RECT *pSrcRect,
583                                                DWORD dwFilter,
584                                                D3DCOLOR Colorkey,
585                                                D3DXIMAGE_INFO *pSrcInfo)
586 {
587     D3DXIMAGE_INFO imginfo;
588     HRESULT hr;
589
590     IWICImagingFactory *factory;
591     IWICBitmapDecoder *decoder;
592     IWICBitmapFrameDecode *bitmapframe;
593     IWICStream *stream;
594
595     const PixelFormatDesc *formatdesc;
596     WICRect wicrect;
597     RECT rect;
598
599     TRACE("(%p, %p, %p, %p, %d, %p, %d, %x, %p)\n", pDestSurface, pDestPalette, pDestRect, pSrcData,
600         SrcDataSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
601
602     if (!pDestSurface || !pSrcData || !SrcDataSize)
603         return D3DERR_INVALIDCALL;
604
605     hr = D3DXGetImageInfoFromFileInMemory(pSrcData, SrcDataSize, &imginfo);
606
607     if (FAILED(hr))
608         return hr;
609
610     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
611
612     if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory)))
613         goto cleanup_err;
614
615     if (FAILED(IWICImagingFactory_CreateStream(factory, &stream)))
616     {
617         IWICImagingFactory_Release(factory);
618         goto cleanup_err;
619     }
620
621     IWICStream_InitializeFromMemory(stream, (BYTE*)pSrcData, SrcDataSize);
622
623     hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
624
625     IStream_Release(stream);
626     IWICImagingFactory_Release(factory);
627
628     if (FAILED(hr))
629         goto cleanup_err;
630
631     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &bitmapframe);
632
633     if (FAILED(hr))
634         goto cleanup_bmp;
635
636     if (pSrcRect)
637     {
638         wicrect.X = pSrcRect->left;
639         wicrect.Y = pSrcRect->top;
640         wicrect.Width = pSrcRect->right - pSrcRect->left;
641         wicrect.Height = pSrcRect->bottom - pSrcRect->top;
642     }
643     else
644     {
645         wicrect.X = 0;
646         wicrect.Y = 0;
647         wicrect.Width = imginfo.Width;
648         wicrect.Height = imginfo.Height;
649     }
650
651     SetRect(&rect, 0, 0, wicrect.Width, wicrect.Height);
652
653     formatdesc = get_format_info(imginfo.Format);
654
655     if (formatdesc->format == D3DFMT_UNKNOWN)
656     {
657         FIXME("Unsupported pixel format\n");
658         hr = D3DXERR_INVALIDDATA;
659     }
660     else
661     {
662         BYTE *buffer;
663         DWORD pitch;
664
665         pitch = formatdesc->bytes_per_pixel * wicrect.Width;
666         buffer = HeapAlloc(GetProcessHeap(), 0, pitch * wicrect.Height);
667
668         hr = IWICBitmapFrameDecode_CopyPixels(bitmapframe, &wicrect, pitch,
669                                               pitch * wicrect.Height, buffer);
670
671         if (SUCCEEDED(hr))
672         {
673             hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
674                                            buffer, imginfo.Format, pitch,
675                                            NULL, &rect, dwFilter, Colorkey);
676         }
677
678         HeapFree(GetProcessHeap(), 0, buffer);
679     }
680
681     IWICBitmapFrameDecode_Release(bitmapframe);
682
683 cleanup_bmp:
684     IWICBitmapDecoder_Release(decoder);
685
686 cleanup_err:
687     CoUninitialize();
688
689     if (FAILED(hr))
690         return D3DXERR_INVALIDDATA;
691
692     if (pSrcInfo)
693         *pSrcInfo = imginfo;
694
695     return D3D_OK;
696 }
697
698 /************************************************************
699  * D3DXLoadSurfaceFromFile
700  */
701 HRESULT WINAPI D3DXLoadSurfaceFromFileA(LPDIRECT3DSURFACE9 pDestSurface,
702                                         CONST PALETTEENTRY *pDestPalette,
703                                         CONST RECT *pDestRect,
704                                         LPCSTR pSrcFile,
705                                         CONST RECT *pSrcRect,
706                                         DWORD dwFilter,
707                                         D3DCOLOR Colorkey,
708                                         D3DXIMAGE_INFO *pSrcInfo)
709 {
710     LPWSTR pWidename;
711     HRESULT hr;
712     int strlength;
713
714     TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_a(pSrcFile),
715         pSrcRect, dwFilter, Colorkey, pSrcInfo);
716
717     if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
718
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);
722
723     hr = D3DXLoadSurfaceFromFileW(pDestSurface, pDestPalette, pDestRect, pWidename, pSrcRect, dwFilter, Colorkey, pSrcInfo);
724     HeapFree(GetProcessHeap(), 0, pWidename);
725
726     return hr;
727 }
728
729 HRESULT WINAPI D3DXLoadSurfaceFromFileW(LPDIRECT3DSURFACE9 pDestSurface,
730                                         CONST PALETTEENTRY *pDestPalette,
731                                         CONST RECT *pDestRect,
732                                         LPCWSTR pSrcFile,
733                                         CONST RECT *pSrcRect,
734                                         DWORD Filter,
735                                         D3DCOLOR Colorkey,
736                                         D3DXIMAGE_INFO *pSrcInfo)
737 {
738     HRESULT hr;
739     DWORD dwSize;
740     LPVOID pBuffer;
741
742     TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_w(pSrcFile),
743         pSrcRect, Filter, Colorkey, pSrcInfo);
744
745     if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
746
747     hr = map_view_of_file(pSrcFile, &pBuffer, &dwSize);
748     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
749
750     hr = D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, Filter, Colorkey, pSrcInfo);
751     UnmapViewOfFile(pBuffer);
752
753     return hr;
754 }
755
756 /************************************************************
757  * D3DXLoadSurfaceFromResource
758  */
759 HRESULT WINAPI D3DXLoadSurfaceFromResourceA(LPDIRECT3DSURFACE9 pDestSurface,
760                                             CONST PALETTEENTRY *pDestPalette,
761                                             CONST RECT *pDestRect,
762                                             HMODULE hSrcModule,
763                                             LPCSTR pResource,
764                                             CONST RECT *pSrcRect,
765                                             DWORD dwFilter,
766                                             D3DCOLOR Colorkey,
767                                             D3DXIMAGE_INFO *pSrcInfo)
768 {
769     HRSRC hResInfo;
770
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);
773
774     if( !pDestSurface ) return D3DERR_INVALIDCALL;
775
776     hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_RCDATA);
777     if(hResInfo) {
778         LPVOID pBuffer;
779         HRESULT hr;
780         DWORD dwSize;
781
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);
785     }
786
787     hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_BITMAP);
788     if(hResInfo) {
789         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
790         return E_NOTIMPL;
791     }
792     return D3DXERR_INVALIDDATA;
793 }
794
795 HRESULT WINAPI D3DXLoadSurfaceFromResourceW(LPDIRECT3DSURFACE9 pDestSurface,
796                                             CONST PALETTEENTRY *pDestPalette,
797                                             CONST RECT *pDestRect,
798                                             HMODULE hSrcModule,
799                                             LPCWSTR pResource,
800                                             CONST RECT *pSrcRect,
801                                             DWORD dwFilter,
802                                             D3DCOLOR Colorkey,
803                                             D3DXIMAGE_INFO *pSrcInfo)
804 {
805     HRSRC hResInfo;
806
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);
809
810     if( !pDestSurface ) return D3DERR_INVALIDCALL;
811
812     hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_RCDATA);
813     if(hResInfo) {
814         LPVOID pBuffer;
815         HRESULT hr;
816         DWORD dwSize;
817
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);
821     }
822
823     hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_BITMAP);
824     if(hResInfo) {
825         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
826         return E_NOTIMPL;
827     }
828     return D3DXERR_INVALIDDATA;
829 }
830
831
832 /************************************************************
833  * helper functions for D3DXLoadSurfaceFromMemory
834  */
835 struct argb_conversion_info
836 {
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];
842     DWORD channelmask;
843 };
844
845 static void init_argb_conversion_info(CONST PixelFormatDesc *srcformat, CONST PixelFormatDesc *destformat, struct argb_conversion_info *info)
846 {
847     UINT i;
848     ZeroMemory(info->process_channel, 4 * sizeof(BOOL));
849     info->channelmask = 0;
850
851     info->srcformat  =  srcformat;
852     info->destformat = destformat;
853
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);
857
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);
860
861         info->srcmask[i]  = ((1 <<  srcformat->bits[i]) - 1) <<  srcformat->shift[i];
862         info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i];
863
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];
868         }
869     }
870 }
871
872 static DWORD dword_from_bytes(CONST BYTE *src, UINT bytes_per_pixel)
873 {
874     DWORD ret = 0;
875     static BOOL fixme_once;
876
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);
880     }
881
882     memcpy(&ret, src, bytes_per_pixel);
883     return ret;
884 }
885
886 static void dword_to_bytes(BYTE *dst, DWORD dword, UINT bytes_per_pixel)
887 {
888     static BOOL fixme_once;
889
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);
894     }
895
896     memcpy(dst, &dword, bytes_per_pixel);
897 }
898
899 /************************************************************
900  * get_relevant_argb_components
901  *
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.
904  */
905 static void get_relevant_argb_components(CONST struct argb_conversion_info *info, CONST DWORD col, DWORD *out)
906 {
907     UINT i = 0;
908     for(;i < 4;i++)
909         if(info->process_channel[i])
910             out[i] = (col & info->srcmask[i]) >> info->srcshift[i];
911 }
912
913 /************************************************************
914  * make_argb_color
915  *
916  * Recombines the output of get_relevant_argb_components and converts
917  * it to the destination format.
918  */
919 static DWORD make_argb_color(CONST struct argb_conversion_info *info, CONST DWORD *in)
920 {
921     UINT i;
922     DWORD val = 0;
923
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 */
927             signed int shift;
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];
930         }
931     }
932     val |= info->channelmask;   /* new channels are set to their maximal value */
933     return val;
934 }
935
936 static void format_to_vec4(const PixelFormatDesc *format, const DWORD *src, struct vec4 *dst)
937 {
938     DWORD mask;
939
940     if (format->bits[1])
941     {
942         mask = (1 << format->bits[1]) - 1;
943         dst->x = (float)((*src >> format->shift[1]) & mask) / mask;
944     }
945     else
946         dst->x = 1.0f;
947
948     if (format->bits[2])
949     {
950         mask = (1 << format->bits[2]) - 1;
951         dst->y = (float)((*src >> format->shift[2]) & mask) / mask;
952     }
953     else
954         dst->y = 1.0f;
955
956     if (format->bits[3])
957     {
958         mask = (1 << format->bits[3]) - 1;
959         dst->z = (float)((*src >> format->shift[3]) & mask) / mask;
960     }
961     else
962         dst->z = 1.0f;
963
964     if (format->bits[0])
965     {
966         mask = (1 << format->bits[0]) - 1;
967         dst->w = (float)((*src >> format->shift[0]) & mask) / mask;
968     }
969     else
970         dst->w = 1.0f;
971 }
972
973 static void format_from_vec4(const PixelFormatDesc *format, const struct vec4 *src, DWORD *dst)
974 {
975     *dst = 0;
976
977     if (format->bits[1])
978         *dst |= (DWORD)(src->x * ((1 << format->bits[1]) - 1) + 0.5f) << format->shift[1];
979     if (format->bits[2])
980         *dst |= (DWORD)(src->y * ((1 << format->bits[2]) - 1) + 0.5f) << format->shift[2];
981     if (format->bits[3])
982         *dst |= (DWORD)(src->z * ((1 << format->bits[3]) - 1) + 0.5f) << format->shift[3];
983     if (format->bits[0])
984         *dst |= (DWORD)(src->w * ((1 << format->bits[0]) - 1) + 0.5f) << format->shift[0];
985 }
986
987 /************************************************************
988  * copy_simple_data
989  *
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.
994  */
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)
997 {
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;
1002     UINT x, y;
1003
1004     ZeroMemory(channels, sizeof(channels));
1005     init_argb_conversion_info(srcformat, destformat, &conv_info);
1006
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;
1009
1010     if (colorkey)
1011     {
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);
1015     }
1016
1017     for(y = 0;y < minheight;y++) {
1018         const BYTE *srcptr = src + y * srcpitch;
1019         BYTE *destptr = dest + y * destpitch;
1020         DWORD val;
1021
1022         for(x = 0;x < minwidth;x++) {
1023             /* extract source color components */
1024             pixel = dword_from_bytes(srcptr, srcformat->bytes_per_pixel);
1025
1026             if (!srcformat->to_rgba && !destformat->from_rgba)
1027             {
1028                 get_relevant_argb_components(&conv_info, pixel, channels);
1029                 val = make_argb_color(&conv_info, channels);
1030
1031                 if (colorkey)
1032                 {
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];
1037                 }
1038             }
1039             else
1040             {
1041                 struct vec4 color, tmp;
1042
1043                 format_to_vec4(srcformat, &pixel, &color);
1044                 if (srcformat->to_rgba)
1045                     srcformat->to_rgba(&color, &tmp);
1046                 else
1047                     tmp = color;
1048
1049                 if (ck_format)
1050                 {
1051                     format_from_vec4(ck_format, &tmp, &pixel);
1052                     if (pixel == colorkey)
1053                         tmp.w = 0.0f;
1054                 }
1055
1056                 if (destformat->from_rgba)
1057                     destformat->from_rgba(&tmp, &color);
1058                 else
1059                     color = tmp;
1060
1061                 format_from_vec4(destformat, &color, &val);
1062             }
1063
1064             dword_to_bytes(destptr, val, destformat->bytes_per_pixel);
1065             srcptr  +=  srcformat->bytes_per_pixel;
1066             destptr += destformat->bytes_per_pixel;
1067         }
1068
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));
1071     }
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));
1074 }
1075
1076 /************************************************************
1077  * point_filter_simple_data
1078  *
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.
1083  */
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)
1086 {
1087     struct argb_conversion_info conv_info, ck_conv_info;
1088     const PixelFormatDesc *ck_format = NULL;
1089     DWORD channels[4], pixel;
1090
1091     UINT x, y;
1092
1093     ZeroMemory(channels, sizeof(channels));
1094     init_argb_conversion_info(srcformat, destformat, &conv_info);
1095
1096     if (colorkey)
1097     {
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);
1101     }
1102
1103     for (y = 0; y < dst_size.cy; ++y)
1104     {
1105         BYTE *destptr = dest + y * destpitch;
1106         const BYTE *bufptr = src + srcpitch * (y * src_size.cy / dst_size.cy);
1107
1108         for (x = 0; x < dst_size.cx; ++x)
1109         {
1110             const BYTE *srcptr = bufptr + (x * src_size.cx / dst_size.cx) * srcformat->bytes_per_pixel;
1111             DWORD val;
1112
1113             /* extract source color components */
1114             pixel = dword_from_bytes(srcptr, srcformat->bytes_per_pixel);
1115
1116             if (!srcformat->to_rgba && !destformat->from_rgba)
1117             {
1118                 get_relevant_argb_components(&conv_info, pixel, channels);
1119                 val = make_argb_color(&conv_info, channels);
1120
1121                 if (colorkey)
1122                 {
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];
1127                 }
1128             }
1129             else
1130             {
1131                 struct vec4 color, tmp;
1132
1133                 format_to_vec4(srcformat, &pixel, &color);
1134                 if (srcformat->to_rgba)
1135                     srcformat->to_rgba(&color, &tmp);
1136                 else
1137                     tmp = color;
1138
1139                 if (ck_format)
1140                 {
1141                     format_from_vec4(ck_format, &tmp, &pixel);
1142                     if (pixel == colorkey)
1143                         tmp.w = 0.0f;
1144                 }
1145
1146                 if (destformat->from_rgba)
1147                     destformat->from_rgba(&tmp, &color);
1148                 else
1149                     color = tmp;
1150
1151                 format_from_vec4(destformat, &color, &val);
1152             }
1153
1154             dword_to_bytes(destptr, val, destformat->bytes_per_pixel);
1155             destptr += destformat->bytes_per_pixel;
1156         }
1157     }
1158 }
1159
1160 /************************************************************
1161  * D3DXLoadSurfaceFromMemory
1162  *
1163  * Loads data from a given memory chunk into a surface,
1164  * applying any of the specified filters.
1165  *
1166  * PARAMS
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
1177  *
1178  * RETURNS
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
1186  *
1187  * NOTES
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.
1190  *
1191  */
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)
1196 {
1197     CONST PixelFormatDesc *srcformatdesc, *destformatdesc;
1198     D3DSURFACE_DESC surfdesc;
1199     D3DLOCKED_RECT lockrect;
1200     SIZE src_size, dst_size;
1201     HRESULT hr;
1202
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);
1206
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)
1212         return E_FAIL;
1213
1214     if (filter == D3DX_DEFAULT)
1215         filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
1216
1217     IDirect3DSurface9_GetDesc(dst_surface, &surfdesc);
1218
1219     src_size.cx = src_rect->right - src_rect->left;
1220     src_size.cy = src_rect->bottom - src_rect->top;
1221     if (!dst_rect)
1222     {
1223         dst_size.cx = surfdesc.Width;
1224         dst_size.cy = surfdesc.Height;
1225     }
1226     else
1227     {
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)
1237             return D3D_OK;
1238     }
1239
1240     srcformatdesc = get_format_info(src_format);
1241     if (srcformatdesc->type == FORMAT_UNKNOWN)
1242         return E_NOTIMPL;
1243
1244     destformatdesc = get_format_info(surfdesc.Format);
1245     if (destformatdesc->type == FORMAT_UNKNOWN)
1246         return E_NOTIMPL;
1247
1248     if (src_format == surfdesc.Format
1249             && dst_size.cx == src_size.cx
1250             && dst_size.cy == src_size.cy) /* Simple copy. */
1251     {
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;
1255         BYTE *dst_addr;
1256         UINT row;
1257
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))
1264         {
1265             WARN("Source rect %s is misaligned.\n", wine_dbgstr_rect(src_rect));
1266             return D3DXERR_INVALIDDATA;
1267         }
1268
1269         if (FAILED(hr = IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
1270             return D3DXERR_INVALIDDATA;
1271
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;
1276
1277         for (row = 0; row < row_count; ++row)
1278         {
1279             memcpy(dst_addr, src_addr, row_block_count * srcformatdesc->block_byte_count);
1280             src_addr += src_pitch;
1281             dst_addr += lockrect.Pitch;
1282         }
1283
1284         IDirect3DSurface9_UnlockRect(dst_surface);
1285     }
1286     else /* Stretching or format conversion. */
1287     {
1288         if (srcformatdesc->bytes_per_pixel > 4)
1289             return E_NOTIMPL;
1290         if (destformatdesc->bytes_per_pixel > 4)
1291             return E_NOTIMPL;
1292         if (srcformatdesc->block_height != 1 || srcformatdesc->block_width != 1)
1293             return E_NOTIMPL;
1294         if (destformatdesc->block_height != 1 || destformatdesc->block_width != 1)
1295             return E_NOTIMPL;
1296
1297         if (FAILED(hr = IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
1298             return D3DXERR_INVALIDDATA;
1299
1300         if ((filter & 0xf) == D3DX_FILTER_NONE)
1301         {
1302             copy_simple_data(src_memory, src_pitch, src_size, srcformatdesc,
1303                     lockrect.pBits, lockrect.Pitch, dst_size, destformatdesc, color_key);
1304         }
1305         else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */
1306         {
1307             if ((filter & 0xf) != D3DX_FILTER_POINT)
1308                 FIXME("Unhandled filter %#x.\n", filter);
1309
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);
1314         }
1315
1316         IDirect3DSurface9_UnlockRect(dst_surface);
1317     }
1318
1319     return D3D_OK;
1320 }
1321
1322 /************************************************************
1323  * D3DXLoadSurfaceFromSurface
1324  *
1325  * Copies the contents from one surface to another, performing any required
1326  * format conversion, resizing or filtering.
1327  *
1328  * PARAMS
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
1337  *
1338  * RETURNS
1339  *   Success: D3D_OK
1340  *   Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
1341  *            D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
1342  *
1343  */
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,
1350                                           DWORD dwFilter,
1351                                           D3DCOLOR Colorkey)
1352 {
1353     RECT rect;
1354     D3DLOCKED_RECT lock;
1355     D3DSURFACE_DESC SrcDesc;
1356     HRESULT hr;
1357
1358     TRACE("(%p, %p, %p, %p, %p, %p, %u, %#x): relay\n", pDestSurface, pDestPalette, pDestRect,
1359         pSrcSurface, pSrcPalette, pSrcRect, dwFilter, Colorkey);
1360
1361     if( !pDestSurface || !pSrcSurface ) return D3DERR_INVALIDCALL;
1362
1363     IDirect3DSurface9_GetDesc(pSrcSurface, &SrcDesc);
1364
1365     if( !pSrcRect ) SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height);
1366     else rect = *pSrcRect;
1367
1368     hr = IDirect3DSurface9_LockRect(pSrcSurface, &lock, NULL, D3DLOCK_READONLY);
1369     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
1370
1371     hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
1372                                    lock.pBits, SrcDesc.Format, lock.Pitch,
1373                                    pSrcPalette, &rect, dwFilter, Colorkey);
1374
1375     IDirect3DSurface9_UnlockRect(pSrcSurface);
1376     return hr;
1377 }
1378
1379
1380 HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1381         IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1382 {
1383     int len;
1384     WCHAR *filename;
1385     HRESULT hr;
1386
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));
1389
1390     if (!dst_filename) return D3DERR_INVALIDCALL;
1391
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);
1396
1397     hr = D3DXSaveSurfaceToFileW(filename, file_format, src_surface, src_palette, src_rect);
1398
1399     HeapFree(GetProcessHeap(), 0, filename);
1400     return hr;
1401 }
1402
1403 HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1404         IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
1405 {
1406     IWICImagingFactory *factory;
1407     IWICBitmapEncoder *encoder = NULL;
1408     IWICBitmapFrameEncode *frame = NULL;
1409     IPropertyBag2 *encoder_options = NULL;
1410     IWICStream *stream = NULL;
1411     HRESULT hr;
1412     HRESULT initresult;
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;
1419     int width, height;
1420
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));
1423
1424     if (!dst_filename || !src_surface) return D3DERR_INVALIDCALL;
1425
1426     if (src_palette)
1427     {
1428         FIXME("Saving surfaces with palettized pixel formats not implemented yet\n");
1429         return D3DERR_INVALIDCALL;
1430     }
1431
1432     switch (file_format)
1433     {
1434         case D3DXIFF_BMP:
1435             encoder_clsid = &CLSID_WICBmpEncoder;
1436             break;
1437         case D3DXIFF_PNG:
1438             encoder_clsid = &CLSID_WICPngEncoder;
1439             break;
1440         case D3DXIFF_JPG:
1441             encoder_clsid = &CLSID_WICJpegEncoder;
1442             break;
1443         case D3DXIFF_DDS:
1444         case D3DXIFF_DIB:
1445         case D3DXIFF_HDR:
1446         case D3DXIFF_PFM:
1447         case D3DXIFF_TGA:
1448         case D3DXIFF_PPM:
1449             FIXME("File format %#x is not supported yet\n", file_format);
1450             return E_NOTIMPL;
1451         default:
1452             return D3DERR_INVALIDCALL;
1453     }
1454
1455     IDirect3DSurface9_GetDesc(src_surface, &src_surface_desc);
1456     if (src_rect)
1457     {
1458         if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom)
1459             return D3D_OK;
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;
1466
1467         width = src_rect->right - src_rect->left;
1468         height = src_rect->bottom - src_rect->top;
1469     }
1470     else
1471     {
1472         width = src_surface_desc.Width;
1473         height = src_surface_desc.Height;
1474     }
1475
1476     initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1477
1478     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1479         &IID_IWICImagingFactory, (void **)&factory);
1480     if (FAILED(hr)) goto cleanup_err;
1481
1482     hr = IWICImagingFactory_CreateStream(factory, &stream);
1483     IWICImagingFactory_Release(factory);
1484     if (FAILED(hr)) goto cleanup_err;
1485
1486     hr = IWICStream_InitializeFromFilename(stream, dst_filename, GENERIC_WRITE);
1487     if (FAILED(hr)) goto cleanup_err;
1488
1489     hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1490         &IID_IWICBitmapEncoder, (void **)&encoder);
1491     if (FAILED(hr)) goto cleanup_err;
1492
1493     hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)stream, WICBitmapEncoderNoCache);
1494     IStream_Release((IStream *)stream);
1495     stream = NULL;
1496     if (FAILED(hr)) goto cleanup_err;
1497
1498     hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options);
1499     if (FAILED(hr)) goto cleanup_err;
1500
1501     hr = IWICBitmapFrameEncode_Initialize(frame, encoder_options);
1502     if (FAILED(hr)) goto cleanup_err;
1503
1504     hr = IWICBitmapFrameEncode_SetSize(frame, width, height);
1505     if (FAILED(hr)) goto cleanup_err;
1506
1507     pixel_format_guid = d3dformat_to_wic_guid(src_surface_desc.Format);
1508     if (!pixel_format_guid)
1509     {
1510         FIXME("Pixel format %#x is not supported yet\n", src_surface_desc.Format);
1511         hr = E_NOTIMPL;
1512         goto cleanup;
1513     }
1514
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)
1519     {
1520         TRACE("Using pixel format %s %#x\n", debugstr_guid(&wic_pixel_format), d3d_pixel_format);
1521
1522         if (src_surface_desc.Format == d3d_pixel_format) /* Simple copy */
1523         {
1524             hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY);
1525             if (SUCCEEDED(hr))
1526             {
1527                 IWICBitmapFrameEncode_WritePixels(frame, height,
1528                     locked_rect.Pitch, height * locked_rect.Pitch, locked_rect.pBits);
1529                 IDirect3DSurface9_UnlockRect(src_surface);
1530             }
1531         }
1532         else /* Pixel format conversion */
1533         {
1534             const PixelFormatDesc *src_format_desc, *dst_format_desc;
1535             SIZE size;
1536             DWORD dst_pitch;
1537             void *dst_data;
1538
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)
1542             {
1543                 FIXME("Unsupported pixel format conversion %#x -> %#x\n",
1544                     src_surface_desc.Format, d3d_pixel_format);
1545                 hr = E_NOTIMPL;
1546                 goto cleanup;
1547             }
1548
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)
1553             {
1554                 hr = E_NOTIMPL;
1555                 goto cleanup;
1556             }
1557
1558             size.cx = width;
1559             size.cy = height;
1560             dst_pitch = width * dst_format_desc->bytes_per_pixel;
1561             dst_data = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height);
1562             if (!dst_data)
1563             {
1564                 hr = E_OUTOFMEMORY;
1565                 goto cleanup;
1566             }
1567
1568             hr = IDirect3DSurface9_LockRect(src_surface, &locked_rect, src_rect, D3DLOCK_READONLY);
1569             if (SUCCEEDED(hr))
1570             {
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);
1574             }
1575
1576             IWICBitmapFrameEncode_WritePixels(frame, height, dst_pitch, dst_pitch * height, dst_data);
1577             HeapFree(GetProcessHeap(), 0, dst_data);
1578         }
1579
1580         hr = IWICBitmapFrameEncode_Commit(frame);
1581         if (SUCCEEDED(hr)) hr = IWICBitmapEncoder_Commit(encoder);
1582     }
1583     else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format);
1584
1585 cleanup_err:
1586     if (FAILED(hr)) hr = D3DERR_INVALIDCALL;
1587
1588 cleanup:
1589     if (stream) IStream_Release((IStream *)stream);
1590
1591     if (frame) IWICBitmapFrameEncode_Release(frame);
1592     if (encoder_options) IPropertyBag2_Release(encoder_options);
1593
1594     if (encoder) IWICBitmapEncoder_Release(encoder);
1595
1596     if (SUCCEEDED(initresult)) CoUninitialize();
1597
1598     return hr;
1599 }