d3dx9_36: Turn FIXME into TRACE since function is implemented. Not supported formats...
[wine] / dlls / d3dx9_36 / surface.c
1 /*
2  * Copyright (C) 2009-2010 Tony Wasserka
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  */
19
20 #include "wine/debug.h"
21 #include "wine/unicode.h"
22 #include "d3dx9_36_private.h"
23
24 #include "initguid.h"
25 #include "wincodec.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
28
29
30 /* Wine-specific WIC GUIDs */
31
32 DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22);
33
34 /************************************************************
35  * D3DXGetImageInfoFromFileInMemory
36  *
37  * Fills a D3DXIMAGE_INFO structure with info about an image
38  *
39  * PARAMS
40  *   data     [I] pointer to the image file data
41  *   datasize [I] size of the passed data
42  *   info     [O] pointer to the destination structure
43  *
44  * RETURNS
45  *   Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or
46  *                    if info is NULL and data and datasize are not NULL
47  *   Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL
48  *            D3DERR_INVALIDCALL, if data is NULL or
49  *                                if datasize is 0
50  *
51  * NOTES
52  *   datasize may be bigger than the actual file size
53  *
54  */
55 HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(LPCVOID data, UINT datasize, D3DXIMAGE_INFO *info)
56 {
57     IWICImagingFactory *factory;
58     IWICBitmapDecoder *decoder = NULL;
59     IWICStream *stream;
60     HRESULT hr;
61     HRESULT initresult;
62
63     TRACE("(%p, %d, %p)\n", data, datasize, info);
64
65     /* TODO: Add support for (or at least detect) DDS, PPM and DIB */
66
67     if (!data || !datasize)
68         return D3DERR_INVALIDCALL;
69
70     if (!info)
71         return D3D_OK;
72
73     initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
74
75     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory);
76
77     if (SUCCEEDED(hr)) {
78         IWICImagingFactory_CreateStream(factory, &stream);
79         IWICStream_InitializeFromMemory(stream, (BYTE*)data, datasize);
80         hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
81         IStream_Release(stream);
82         IWICImagingFactory_Release(factory);
83     }
84
85     if (SUCCEEDED(hr)) {
86         GUID container_format;
87         UINT frame_count;
88
89         hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format);
90         if (SUCCEEDED(hr)) {
91             if (IsEqualGUID(&container_format, &GUID_ContainerFormatBmp)) {
92                 TRACE("File type is BMP\n");
93                 info->ImageFileFormat = D3DXIFF_BMP;
94             } else if (IsEqualGUID(&container_format, &GUID_ContainerFormatPng)) {
95                 TRACE("File type is PNG\n");
96                 info->ImageFileFormat = D3DXIFF_PNG;
97             } else if(IsEqualGUID(&container_format, &GUID_ContainerFormatJpeg)) {
98                 TRACE("File type is JPG\n");
99                 info->ImageFileFormat = D3DXIFF_JPG;
100             } else if(IsEqualGUID(&container_format, &GUID_WineContainerFormatTga)) {
101                 TRACE("File type is TGA\n");
102                 info->ImageFileFormat = D3DXIFF_TGA;
103             } else {
104                 WARN("Unsupported image file format %s\n", debugstr_guid(&container_format));
105                 hr = D3DXERR_INVALIDDATA;
106             }
107         }
108
109         if (SUCCEEDED(hr))
110             hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
111         if (SUCCEEDED(hr) && !frame_count)
112             hr = D3DXERR_INVALIDDATA;
113
114         if (SUCCEEDED(hr)) {
115             IWICBitmapFrameDecode *frame = NULL;
116
117             hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
118
119             if (SUCCEEDED(hr))
120                 hr = IWICBitmapFrameDecode_GetSize(frame, &info->Width, &info->Height);
121
122             if (SUCCEEDED(hr)) {
123                 WICPixelFormatGUID pixel_format;
124
125                 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &pixel_format);
126                 if (SUCCEEDED(hr)) {
127                     if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat1bppIndexed))
128                         info->Format = D3DFMT_L8;
129                     else if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat4bppIndexed))
130                         info->Format = D3DFMT_L8;
131                     else if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat8bppIndexed))
132                         info->Format = D3DFMT_L8;
133                     else if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat16bppBGR555))
134                         info->Format = D3DFMT_X1R5G5B5;
135                     else if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat24bppBGR))
136                         info->Format = D3DFMT_R8G8B8;
137                     else if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat32bppBGR))
138                         info->Format = D3DFMT_X8R8G8B8;
139                     else if (IsEqualGUID(&pixel_format, &GUID_WICPixelFormat32bppBGRA))
140                         info->Format = D3DFMT_A8R8G8B8;
141                     else {
142                         WARN("Unsupported pixel format %s\n", debugstr_guid(&pixel_format));
143                         hr = D3DXERR_INVALIDDATA;
144                     }
145                 }
146             }
147
148             if (frame)
149                  IWICBitmapFrameDecode_Release(frame);
150
151             info->Depth = 1;
152             info->MipLevels = 1;
153             info->ResourceType = D3DRTYPE_TEXTURE;
154         }
155     }
156
157     if (decoder)
158         IWICBitmapDecoder_Release(decoder);
159
160     if (SUCCEEDED(initresult))
161         CoUninitialize();
162
163     if (FAILED(hr)) {
164         /* Missing formats are not detected yet and will fail silently without the FIXME */
165         FIXME("Invalid or unsupported image file\n");
166         return D3DXERR_INVALIDDATA;
167     }
168
169     return D3D_OK;
170 }
171
172 /************************************************************
173  * D3DXGetImageInfoFromFile
174  *
175  * RETURNS
176  *   Success: D3D_OK, if we successfully load a valid image file or
177  *                    if we successfully load a file which is no valid image and info is NULL
178  *   Failure: D3DXERR_INVALIDDATA, if we fail to load file or
179  *                                 if file is not a valid image file and info is not NULL
180  *            D3DERR_INVALIDCALL, if file is NULL
181  *
182  */
183 HRESULT WINAPI D3DXGetImageInfoFromFileA(LPCSTR file, D3DXIMAGE_INFO *info)
184 {
185     LPWSTR widename;
186     HRESULT hr;
187     int strlength;
188
189     TRACE("(%s, %p): relay\n", debugstr_a(file), info);
190
191     if( !file ) return D3DERR_INVALIDCALL;
192
193     strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0);
194     widename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlength * sizeof(WCHAR));
195     MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength);
196
197     hr = D3DXGetImageInfoFromFileW(widename, info);
198     HeapFree(GetProcessHeap(), 0, widename);
199
200     return hr;
201 }
202
203 HRESULT WINAPI D3DXGetImageInfoFromFileW(LPCWSTR file, D3DXIMAGE_INFO *info)
204 {
205     HRESULT hr;
206     DWORD size;
207     LPVOID buffer;
208
209     TRACE("(%s, %p): relay\n", debugstr_w(file), info);
210
211     if( !file ) return D3DERR_INVALIDCALL;
212
213     hr = map_view_of_file(file, &buffer, &size);
214     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
215
216     hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info);
217     UnmapViewOfFile(buffer);
218
219     return hr;
220 }
221
222 /************************************************************
223  * D3DXGetImageInfoFromResource
224  *
225  * RETURNS
226  *   Success: D3D_OK, if resource is a valid image file
227  *   Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or
228  *                                 if we fail to load resource
229  *
230  */
231 HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, LPCSTR resource, D3DXIMAGE_INFO *info)
232 {
233     HRSRC resinfo;
234
235     TRACE("(%p, %s, %p)\n", module, debugstr_a(resource), info);
236
237     resinfo = FindResourceA(module, resource, (LPCSTR)RT_RCDATA);
238     if(resinfo) {
239         LPVOID buffer;
240         HRESULT hr;
241         DWORD size;
242
243         hr = load_resource_into_memory(module, resinfo, &buffer, &size);
244         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
245         return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
246     }
247
248     resinfo = FindResourceA(module, resource, (LPCSTR)RT_BITMAP);
249     if(resinfo) {
250         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
251         return E_NOTIMPL;
252     }
253     return D3DXERR_INVALIDDATA;
254 }
255
256 HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, LPCWSTR resource, D3DXIMAGE_INFO *info)
257 {
258     HRSRC resinfo;
259
260     TRACE("(%p, %s, %p)\n", module, debugstr_w(resource), info);
261
262     resinfo = FindResourceW(module, resource, (LPCWSTR)RT_RCDATA);
263     if(resinfo) {
264         LPVOID buffer;
265         HRESULT hr;
266         DWORD size;
267
268         hr = load_resource_into_memory(module, resinfo, &buffer, &size);
269         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
270         return D3DXGetImageInfoFromFileInMemory(buffer, size, info);
271     }
272
273     resinfo = FindResourceW(module, resource, (LPCWSTR)RT_BITMAP);
274     if(resinfo) {
275         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
276         return E_NOTIMPL;
277     }
278     return D3DXERR_INVALIDDATA;
279 }
280
281 /************************************************************
282  * D3DXLoadSurfaceFromFileInMemory
283  *
284  * Loads data from a given buffer into a surface and fills a given
285  * D3DXIMAGE_INFO structure with info about the source data.
286  *
287  * PARAMS
288  *   pDestSurface [I] pointer to the surface
289  *   pDestPalette [I] palette to use
290  *   pDestRect    [I] to be filled area of the surface
291  *   pSrcData     [I] pointer to the source data
292  *   SrcDataSize  [I] size of the source data in bytes
293  *   pSrcRect     [I] area of the source data to load
294  *   dwFilter     [I] filter to apply on stretching
295  *   Colorkey     [I] colorkey
296  *   pSrcInfo     [O] pointer to a D3DXIMAGE_INFO structure
297  *
298  * RETURNS
299  *   Success: D3D_OK
300  *   Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcData or SrcDataSize are NULL
301  *            D3DXERR_INVALIDDATA, if pSrcData is no valid image file
302  *
303  */
304 HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(LPDIRECT3DSURFACE9 pDestSurface,
305                                                CONST PALETTEENTRY *pDestPalette,
306                                                CONST RECT *pDestRect,
307                                                LPCVOID pSrcData,
308                                                UINT SrcDataSize,
309                                                CONST RECT *pSrcRect,
310                                                DWORD dwFilter,
311                                                D3DCOLOR Colorkey,
312                                                D3DXIMAGE_INFO *pSrcInfo)
313 {
314     D3DXIMAGE_INFO imginfo;
315     HRESULT hr;
316
317     IWICImagingFactory *factory;
318     IWICBitmapDecoder *decoder;
319     IWICBitmapFrameDecode *bitmapframe;
320     IWICStream *stream;
321
322     const PixelFormatDesc *formatdesc;
323     WICRect wicrect;
324     RECT rect;
325
326     TRACE("(%p, %p, %p, %p, %d, %p, %d, %x, %p)\n", pDestSurface, pDestPalette, pDestRect, pSrcData,
327         SrcDataSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
328
329     if (!pDestSurface || !pSrcData || !SrcDataSize)
330         return D3DERR_INVALIDCALL;
331
332     hr = D3DXGetImageInfoFromFileInMemory(pSrcData, SrcDataSize, &imginfo);
333
334     if (FAILED(hr))
335         return hr;
336
337     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
338
339     if (FAILED(CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (void**)&factory)))
340         goto cleanup_err;
341
342     if (FAILED(IWICImagingFactory_CreateStream(factory, &stream)))
343     {
344         IWICImagingFactory_Release(factory);
345         goto cleanup_err;
346     }
347
348     IWICStream_InitializeFromMemory(stream, (BYTE*)pSrcData, SrcDataSize);
349
350     hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, 0, &decoder);
351
352     IStream_Release(stream);
353     IWICImagingFactory_Release(factory);
354
355     if (FAILED(hr))
356         goto cleanup_err;
357
358     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &bitmapframe);
359
360     if (FAILED(hr))
361         goto cleanup_bmp;
362
363     if (pSrcRect)
364     {
365         wicrect.X = pSrcRect->left;
366         wicrect.Y = pSrcRect->top;
367         wicrect.Width = pSrcRect->right - pSrcRect->left;
368         wicrect.Height = pSrcRect->bottom - pSrcRect->top;
369     }
370     else
371     {
372         wicrect.X = 0;
373         wicrect.Y = 0;
374         wicrect.Width = imginfo.Width;
375         wicrect.Height = imginfo.Height;
376     }
377
378     SetRect(&rect, 0, 0, wicrect.Width, wicrect.Height);
379
380     formatdesc = get_format_info(imginfo.Format);
381
382     if (formatdesc->format == D3DFMT_UNKNOWN)
383     {
384         FIXME("Unsupported pixel format\n");
385         hr = D3DXERR_INVALIDDATA;
386     }
387     else
388     {
389         BYTE *buffer;
390         DWORD pitch;
391
392         pitch = formatdesc->bytes_per_pixel * wicrect.Width;
393         buffer = HeapAlloc(GetProcessHeap(), 0, pitch * wicrect.Height);
394
395         hr = IWICBitmapFrameDecode_CopyPixels(bitmapframe, &wicrect, pitch,
396                                               pitch * wicrect.Height, buffer);
397
398         if (SUCCEEDED(hr))
399         {
400             hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
401                                            buffer, imginfo.Format, pitch,
402                                            NULL, &rect, dwFilter, Colorkey);
403         }
404
405         HeapFree(GetProcessHeap(), 0, buffer);
406     }
407
408     IWICBitmapFrameDecode_Release(bitmapframe);
409
410 cleanup_bmp:
411     IWICBitmapDecoder_Release(decoder);
412
413 cleanup_err:
414     CoUninitialize();
415
416     if (FAILED(hr))
417         return D3DXERR_INVALIDDATA;
418
419     if (pSrcInfo)
420         *pSrcInfo = imginfo;
421
422     return D3D_OK;
423 }
424
425 /************************************************************
426  * D3DXLoadSurfaceFromFile
427  */
428 HRESULT WINAPI D3DXLoadSurfaceFromFileA(LPDIRECT3DSURFACE9 pDestSurface,
429                                         CONST PALETTEENTRY *pDestPalette,
430                                         CONST RECT *pDestRect,
431                                         LPCSTR pSrcFile,
432                                         CONST RECT *pSrcRect,
433                                         DWORD dwFilter,
434                                         D3DCOLOR Colorkey,
435                                         D3DXIMAGE_INFO *pSrcInfo)
436 {
437     LPWSTR pWidename;
438     HRESULT hr;
439     int strlength;
440
441     TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_a(pSrcFile),
442         pSrcRect, dwFilter, Colorkey, pSrcInfo);
443
444     if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
445
446     strlength = MultiByteToWideChar(CP_ACP, 0, pSrcFile, -1, NULL, 0);
447     pWidename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlength * sizeof(WCHAR));
448     MultiByteToWideChar(CP_ACP, 0, pSrcFile, -1, pWidename, strlength);
449
450     hr = D3DXLoadSurfaceFromFileW(pDestSurface, pDestPalette, pDestRect, pWidename, pSrcRect, dwFilter, Colorkey, pSrcInfo);
451     HeapFree(GetProcessHeap(), 0, pWidename);
452
453     return hr;
454 }
455
456 HRESULT WINAPI D3DXLoadSurfaceFromFileW(LPDIRECT3DSURFACE9 pDestSurface,
457                                         CONST PALETTEENTRY *pDestPalette,
458                                         CONST RECT *pDestRect,
459                                         LPCWSTR pSrcFile,
460                                         CONST RECT *pSrcRect,
461                                         DWORD Filter,
462                                         D3DCOLOR Colorkey,
463                                         D3DXIMAGE_INFO *pSrcInfo)
464 {
465     HRESULT hr;
466     DWORD dwSize;
467     LPVOID pBuffer;
468
469     TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_w(pSrcFile),
470         pSrcRect, Filter, Colorkey, pSrcInfo);
471
472     if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
473
474     hr = map_view_of_file(pSrcFile, &pBuffer, &dwSize);
475     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
476
477     hr = D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, Filter, Colorkey, pSrcInfo);
478     UnmapViewOfFile(pBuffer);
479
480     return hr;
481 }
482
483 /************************************************************
484  * D3DXLoadSurfaceFromResource
485  */
486 HRESULT WINAPI D3DXLoadSurfaceFromResourceA(LPDIRECT3DSURFACE9 pDestSurface,
487                                             CONST PALETTEENTRY *pDestPalette,
488                                             CONST RECT *pDestRect,
489                                             HMODULE hSrcModule,
490                                             LPCSTR pResource,
491                                             CONST RECT *pSrcRect,
492                                             DWORD dwFilter,
493                                             D3DCOLOR Colorkey,
494                                             D3DXIMAGE_INFO *pSrcInfo)
495 {
496     HRSRC hResInfo;
497
498     TRACE("(%p, %p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, hSrcModule,
499         debugstr_a(pResource), pSrcRect, dwFilter, Colorkey, pSrcInfo);
500
501     if( !pDestSurface ) return D3DERR_INVALIDCALL;
502
503     hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_RCDATA);
504     if(hResInfo) {
505         LPVOID pBuffer;
506         HRESULT hr;
507         DWORD dwSize;
508
509         hr = load_resource_into_memory(hSrcModule, hResInfo, &pBuffer, &dwSize);
510         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
511         return D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
512     }
513
514     hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_BITMAP);
515     if(hResInfo) {
516         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
517         return E_NOTIMPL;
518     }
519     return D3DXERR_INVALIDDATA;
520 }
521
522 HRESULT WINAPI D3DXLoadSurfaceFromResourceW(LPDIRECT3DSURFACE9 pDestSurface,
523                                             CONST PALETTEENTRY *pDestPalette,
524                                             CONST RECT *pDestRect,
525                                             HMODULE hSrcModule,
526                                             LPCWSTR pResource,
527                                             CONST RECT *pSrcRect,
528                                             DWORD dwFilter,
529                                             D3DCOLOR Colorkey,
530                                             D3DXIMAGE_INFO *pSrcInfo)
531 {
532     HRSRC hResInfo;
533
534     TRACE("(%p, %p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, hSrcModule,
535         debugstr_w(pResource), pSrcRect, dwFilter, Colorkey, pSrcInfo);
536
537     if( !pDestSurface ) return D3DERR_INVALIDCALL;
538
539     hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_RCDATA);
540     if(hResInfo) {
541         LPVOID pBuffer;
542         HRESULT hr;
543         DWORD dwSize;
544
545         hr = load_resource_into_memory(hSrcModule, hResInfo, &pBuffer, &dwSize);
546         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
547         return D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
548     }
549
550     hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_BITMAP);
551     if(hResInfo) {
552         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
553         return E_NOTIMPL;
554     }
555     return D3DXERR_INVALIDDATA;
556 }
557
558
559 /************************************************************
560  * helper functions for D3DXLoadSurfaceFromMemory
561  */
562 struct argb_conversion_info
563 {
564     CONST PixelFormatDesc *srcformat;
565     CONST PixelFormatDesc *destformat;
566     DWORD srcshift[4], destshift[4];
567     DWORD srcmask[4], destmask[4];
568     BOOL process_channel[4];
569     DWORD channelmask;
570 };
571
572 static void init_argb_conversion_info(CONST PixelFormatDesc *srcformat, CONST PixelFormatDesc *destformat, struct argb_conversion_info *info)
573 {
574     UINT i;
575     ZeroMemory(info->process_channel, 4 * sizeof(BOOL));
576     info->channelmask = 0;
577
578     info->srcformat  =  srcformat;
579     info->destformat = destformat;
580
581     for(i = 0;i < 4;i++) {
582         /* srcshift is used to extract the _relevant_ components */
583         info->srcshift[i]  =  srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0);
584
585         /* destshift is used to move the components to the correct position */
586         info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] -  srcformat->bits[i], 0);
587
588         info->srcmask[i]  = ((1 <<  srcformat->bits[i]) - 1) <<  srcformat->shift[i];
589         info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i];
590
591         /* channelmask specifies bits which aren't used in the source format but in the destination one */
592         if(destformat->bits[i]) {
593             if(srcformat->bits[i]) info->process_channel[i] = TRUE;
594             else info->channelmask |= info->destmask[i];
595         }
596     }
597 }
598
599 static DWORD dword_from_bytes(CONST BYTE *src, UINT bytes_per_pixel)
600 {
601     DWORD ret = 0;
602     static BOOL fixme_once;
603
604     if(bytes_per_pixel > sizeof(DWORD)) {
605         if(!fixme_once++) FIXME("Unsupported image: %u bytes per pixel\n", bytes_per_pixel);
606         bytes_per_pixel = sizeof(DWORD);
607     }
608
609     memcpy(&ret, src, bytes_per_pixel);
610     return ret;
611 }
612
613 static void dword_to_bytes(BYTE *dst, DWORD dword, UINT bytes_per_pixel)
614 {
615     static BOOL fixme_once;
616
617     if(bytes_per_pixel > sizeof(DWORD)) {
618         if(!fixme_once++) FIXME("Unsupported image: %u bytes per pixel\n", bytes_per_pixel);
619         ZeroMemory(dst, bytes_per_pixel);
620         bytes_per_pixel = sizeof(DWORD);
621     }
622
623     memcpy(dst, &dword, bytes_per_pixel);
624 }
625
626 /************************************************************
627  * get_relevant_argb_components
628  *
629  * Extracts the relevant components from the source color and
630  * drops the less significant bits if they aren't used by the destination format.
631  */
632 static void get_relevant_argb_components(CONST struct argb_conversion_info *info, CONST DWORD col, DWORD *out)
633 {
634     UINT i = 0;
635     for(;i < 4;i++)
636         if(info->process_channel[i])
637             out[i] = (col & info->srcmask[i]) >> info->srcshift[i];
638 }
639
640 /************************************************************
641  * make_argb_color
642  *
643  * Recombines the output of get_relevant_argb_components and converts
644  * it to the destination format.
645  */
646 static DWORD make_argb_color(CONST struct argb_conversion_info *info, CONST DWORD *in)
647 {
648     UINT i;
649     DWORD val = 0;
650
651     for(i = 0;i < 4;i++) {
652         if(info->process_channel[i]) {
653             /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */
654             signed int shift;
655             for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift;
656             val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i];
657         }
658     }
659     val |= info->channelmask;   /* new channels are set to their maximal value */
660     return val;
661 }
662
663 /************************************************************
664  * copy_simple_data
665  *
666  * Copies the source buffer to the destination buffer, performing
667  * any necessary format conversion and color keying.
668  * Pixels outsize the source rect are blacked out.
669  * Works only for ARGB formats with 1 - 4 bytes per pixel.
670  */
671 static void copy_simple_data(CONST BYTE *src, UINT srcpitch, POINT srcsize,
672                              CONST PixelFormatDesc *srcformat,
673                              BYTE *dest, UINT destpitch, POINT destsize,
674                              CONST PixelFormatDesc *destformat,
675                              D3DCOLOR colorkey)
676 {
677     struct argb_conversion_info conv_info, ck_conv_info;
678     DWORD channels[4], pixel;
679     UINT minwidth, minheight;
680     UINT x, y;
681
682     ZeroMemory(channels, sizeof(channels));
683     init_argb_conversion_info(srcformat, destformat, &conv_info);
684
685     minwidth  = (srcsize.x < destsize.x) ? srcsize.x : destsize.x;
686     minheight = (srcsize.y < destsize.y) ? srcsize.y : destsize.y;
687
688     if(colorkey) {
689         /* color keys are always represented in D3DFMT_A8R8G8B8 format */
690         const PixelFormatDesc *ckformatdesc;
691
692         ckformatdesc = get_format_info(D3DFMT_A8R8G8B8);
693         init_argb_conversion_info(srcformat, ckformatdesc, &ck_conv_info);
694     }
695
696     for(y = 0;y < minheight;y++) {
697         const BYTE *srcptr = src + y * srcpitch;
698         BYTE *destptr = dest + y * destpitch;
699         DWORD val = 0;
700
701         for(x = 0;x < minwidth;x++) {
702             /* extract source color components */
703             pixel = dword_from_bytes(srcptr, srcformat->bytes_per_pixel);
704             get_relevant_argb_components(&conv_info, pixel, channels);
705
706             /* recombine the components */
707             val = make_argb_color(&conv_info, channels);
708
709             if(colorkey) {
710                 get_relevant_argb_components(&ck_conv_info, pixel, channels);
711                 pixel = make_argb_color(&ck_conv_info, channels);
712                 if(pixel == colorkey)
713                     /* make this pixel transparent */
714                     val &= ~conv_info.destmask[0];
715             }
716
717             dword_to_bytes(destptr, val, destformat->bytes_per_pixel);
718             srcptr  +=  srcformat->bytes_per_pixel;
719             destptr += destformat->bytes_per_pixel;
720         }
721
722         if(srcsize.x < destsize.x) /* black out remaining pixels */
723             ZeroMemory(destptr, destformat->bytes_per_pixel * (destsize.x - srcsize.x));
724     }
725     if(srcsize.y < destsize.y) /* black out remaining pixels */
726         ZeroMemory(dest + srcsize.y * destpitch, destpitch * (destsize.y - srcsize.y));
727 }
728
729 /************************************************************
730  * point_filter_simple_data
731  *
732  * Copies the source buffer to the destination buffer, performing
733  * any necessary format conversion, color keying and stretching
734  * using a point filter.
735  * Works only for ARGB formats with 1 - 4 bytes per pixel.
736  */
737 static void point_filter_simple_data(CONST BYTE *src, UINT srcpitch, POINT srcsize,
738                                      CONST PixelFormatDesc *srcformat,
739                                      BYTE *dest, UINT destpitch, POINT destsize,
740                                      CONST PixelFormatDesc *destformat,
741                                      D3DCOLOR colorkey)
742 {
743     struct argb_conversion_info conv_info, ck_conv_info;
744     DWORD channels[4], pixel;
745
746     UINT x, y;
747
748     ZeroMemory(channels, sizeof(channels));
749     init_argb_conversion_info(srcformat, destformat, &conv_info);
750
751     if(colorkey) {
752         /* color keys are always represented in D3DFMT_A8R8G8B8 format */
753         const PixelFormatDesc *ckformatdesc;
754
755         ckformatdesc = get_format_info(D3DFMT_A8R8G8B8);
756         init_argb_conversion_info(srcformat, ckformatdesc, &ck_conv_info);
757     }
758
759     for(y = 0;y < destsize.y;y++) {
760         BYTE *destptr = dest + y * destpitch;
761         const BYTE *bufptr = src + srcpitch * (y * srcsize.y / destsize.y);
762
763         for(x = 0;x < destsize.x;x++) {
764             const BYTE *srcptr = bufptr + (x * srcsize.x / destsize.x) * srcformat->bytes_per_pixel;
765             DWORD val = 0;
766
767             /* extract source color components */
768             pixel = dword_from_bytes(srcptr, srcformat->bytes_per_pixel);
769             get_relevant_argb_components(&conv_info, pixel, channels);
770
771             /* recombine the components */
772             val = make_argb_color(&conv_info, channels);
773
774             if(colorkey) {
775                 get_relevant_argb_components(&ck_conv_info, pixel, channels);
776                 pixel = make_argb_color(&ck_conv_info, channels);
777                 if(pixel == colorkey)
778                     /* make this pixel transparent */
779                     val &= ~conv_info.destmask[0];
780             }
781
782             dword_to_bytes(destptr, val, destformat->bytes_per_pixel);
783             destptr += destformat->bytes_per_pixel;
784         }
785     }
786 }
787
788 /************************************************************
789  * D3DXLoadSurfaceFromMemory
790  *
791  * Loads data from a given memory chunk into a surface,
792  * applying any of the specified filters.
793  *
794  * PARAMS
795  *   pDestSurface [I] pointer to the surface
796  *   pDestPalette [I] palette to use
797  *   pDestRect    [I] to be filled area of the surface
798  *   pSrcMemory   [I] pointer to the source data
799  *   SrcFormat    [I] format of the source pixel data
800  *   SrcPitch     [I] number of bytes in a row
801  *   pSrcPalette  [I] palette used in the source image
802  *   pSrcRect     [I] area of the source data to load
803  *   dwFilter     [I] filter to apply on stretching
804  *   Colorkey     [I] colorkey
805  *
806  * RETURNS
807  *   Success: D3D_OK, if we successfully load the pixel data into our surface or
808  *                    if pSrcMemory is NULL but the other parameters are valid
809  *   Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or
810  *                                if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or
811  *                                if DestRect is invalid
812  *            D3DXERR_INVALIDDATA, if we fail to lock pDestSurface
813  *            E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid
814  *
815  * NOTES
816  *   pSrcRect specifies the dimensions of the source data;
817  *   negative values for pSrcRect are allowed as we're only looking at the width and height anyway.
818  *
819  */
820 HRESULT WINAPI D3DXLoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSurface,
821                                          CONST PALETTEENTRY *pDestPalette,
822                                          CONST RECT *pDestRect,
823                                          LPCVOID pSrcMemory,
824                                          D3DFORMAT SrcFormat,
825                                          UINT SrcPitch,
826                                          CONST PALETTEENTRY *pSrcPalette,
827                                          CONST RECT *pSrcRect,
828                                          DWORD dwFilter,
829                                          D3DCOLOR Colorkey)
830 {
831     CONST PixelFormatDesc *srcformatdesc, *destformatdesc;
832     D3DSURFACE_DESC surfdesc;
833     D3DLOCKED_RECT lockrect;
834     POINT srcsize, destsize;
835     HRESULT hr;
836
837     TRACE("(%p, %p, %p, %p, %x, %u, %p, %p %u, %#x)\n", pDestSurface, pDestPalette, pDestRect, pSrcMemory,
838         SrcFormat, SrcPitch, pSrcPalette, pSrcRect, dwFilter, Colorkey);
839
840     if( !pDestSurface || !pSrcMemory || !pSrcRect ) return D3DERR_INVALIDCALL;
841     if(SrcFormat == D3DFMT_UNKNOWN || pSrcRect->left >= pSrcRect->right || pSrcRect->top >= pSrcRect->bottom) return E_FAIL;
842
843     if(dwFilter == D3DX_DEFAULT) dwFilter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
844
845     IDirect3DSurface9_GetDesc(pDestSurface, &surfdesc);
846
847     srcformatdesc = get_format_info(SrcFormat);
848     destformatdesc = get_format_info(surfdesc.Format);
849     if( srcformatdesc->type == FORMAT_UNKNOWN ||  srcformatdesc->bytes_per_pixel > 4) return E_NOTIMPL;
850     if(destformatdesc->type == FORMAT_UNKNOWN || destformatdesc->bytes_per_pixel > 4) return E_NOTIMPL;
851
852     srcsize.x = pSrcRect->right - pSrcRect->left;
853     srcsize.y = pSrcRect->bottom - pSrcRect->top;
854     if( !pDestRect ) {
855         destsize.x = surfdesc.Width;
856         destsize.y = surfdesc.Height;
857     } else {
858         if(pDestRect->left > pDestRect->right || pDestRect->right > surfdesc.Width) return D3DERR_INVALIDCALL;
859         if(pDestRect->top > pDestRect->bottom || pDestRect->bottom > surfdesc.Height) return D3DERR_INVALIDCALL;
860         if(pDestRect->left < 0 || pDestRect->top < 0) return D3DERR_INVALIDCALL;
861         destsize.x = pDestRect->right - pDestRect->left;
862         destsize.y = pDestRect->bottom - pDestRect->top;
863         if(destsize.x == 0 || destsize.y == 0) return D3D_OK;
864     }
865
866     hr = IDirect3DSurface9_LockRect(pDestSurface, &lockrect, pDestRect, 0);
867     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
868
869     if((dwFilter & 0xF) == D3DX_FILTER_NONE) {
870         copy_simple_data(pSrcMemory, SrcPitch, srcsize, srcformatdesc,
871                          lockrect.pBits, lockrect.Pitch, destsize, destformatdesc,
872                          Colorkey);
873     } else /*if((dwFilter & 0xF) == D3DX_FILTER_POINT) */ {
874         /* always apply a point filter until D3DX_FILTER_LINEAR, D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented */
875         point_filter_simple_data(pSrcMemory, SrcPitch, srcsize, srcformatdesc,
876                                  lockrect.pBits, lockrect.Pitch, destsize, destformatdesc,
877                                  Colorkey);
878     }
879
880     IDirect3DSurface9_UnlockRect(pDestSurface);
881     return D3D_OK;
882 }
883
884 /************************************************************
885  * D3DXLoadSurfaceFromSurface
886  *
887  * Copies the contents from one surface to another, performing any required
888  * format conversion, resizing or filtering.
889  *
890  * PARAMS
891  *   pDestSurface [I] pointer to the destination surface
892  *   pDestPalette [I] palette to use
893  *   pDestRect    [I] to be filled area of the surface
894  *   pSrcSurface  [I] pointer to the source surface
895  *   pSrcPalette  [I] palette used for the source surface
896  *   pSrcRect     [I] area of the source data to load
897  *   dwFilter     [I] filter to apply on resizing
898  *   Colorkey     [I] any ARGB value or 0 to disable color-keying
899  *
900  * RETURNS
901  *   Success: D3D_OK
902  *   Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
903  *            D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
904  *
905  */
906 HRESULT WINAPI D3DXLoadSurfaceFromSurface(LPDIRECT3DSURFACE9 pDestSurface,
907                                           CONST PALETTEENTRY *pDestPalette,
908                                           CONST RECT *pDestRect,
909                                           LPDIRECT3DSURFACE9 pSrcSurface,
910                                           CONST PALETTEENTRY *pSrcPalette,
911                                           CONST RECT *pSrcRect,
912                                           DWORD dwFilter,
913                                           D3DCOLOR Colorkey)
914 {
915     RECT rect;
916     D3DLOCKED_RECT lock;
917     D3DSURFACE_DESC SrcDesc;
918     HRESULT hr;
919
920     TRACE("(%p, %p, %p, %p, %p, %p, %u, %#x): relay\n", pDestSurface, pDestPalette, pDestRect,
921         pSrcSurface, pSrcPalette, pSrcRect, dwFilter, Colorkey);
922
923     if( !pDestSurface || !pSrcSurface ) return D3DERR_INVALIDCALL;
924
925     IDirect3DSurface9_GetDesc(pSrcSurface, &SrcDesc);
926
927     if( !pSrcRect ) SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height);
928     else rect = *pSrcRect;
929
930     hr = IDirect3DSurface9_LockRect(pSrcSurface, &lock, NULL, D3DLOCK_READONLY);
931     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
932
933     hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
934                                    lock.pBits, SrcDesc.Format, lock.Pitch,
935                                    pSrcPalette, &rect, dwFilter, Colorkey);
936
937     IDirect3DSurface9_UnlockRect(pSrcSurface);
938     return hr;
939 }
940
941
942 HRESULT WINAPI D3DXSaveSurfaceToFileA(LPCSTR pDestFile, D3DXIMAGE_FILEFORMAT DestFormat,
943         LPDIRECT3DSURFACE9 pSrcSurface, const PALETTEENTRY* pSrcPalette, const RECT* pSrcRect)
944 {
945     FIXME("(%p, %d, %p, %p, %p): stub\n", pDestFile, DestFormat, pSrcSurface, pSrcPalette, pSrcRect);
946     return D3DERR_INVALIDCALL;
947 }
948
949 HRESULT WINAPI D3DXSaveSurfaceToFileW(LPCWSTR pDestFile, D3DXIMAGE_FILEFORMAT DestFormat,
950         LPDIRECT3DSURFACE9 pSrcSurface, const PALETTEENTRY* pSrcPalette, const RECT* pSrcRect)
951 {
952     FIXME("(%p, %d, %p, %p, %p): stub\n", pDestFile, DestFormat, pSrcSurface, pSrcPalette, pSrcRect);
953     return D3DERR_INVALIDCALL;
954 }