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