windowscodecs: Add locking to the PNG encoder.
[wine] / dlls / d3dx9_36 / surface.c
1 /*
2  * Copyright (C) 2009 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     FIXME("(%p, %p, %p, %p, %d, %p, %d, %x, %p): stub\n", pDestSurface, pDestPalette,
308         pDestRect, pSrcData, SrcDataSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
309
310     if( !pDestSurface || !pSrcData | !SrcDataSize ) return D3DERR_INVALIDCALL;
311     return E_NOTIMPL;
312 }
313
314 /************************************************************
315  * D3DXLoadSurfaceFromFile
316  */
317 HRESULT WINAPI D3DXLoadSurfaceFromFileA(LPDIRECT3DSURFACE9 pDestSurface,
318                                         CONST PALETTEENTRY *pDestPalette,
319                                         CONST RECT *pDestRect,
320                                         LPCSTR pSrcFile,
321                                         CONST RECT *pSrcRect,
322                                         DWORD dwFilter,
323                                         D3DCOLOR Colorkey,
324                                         D3DXIMAGE_INFO *pSrcInfo)
325 {
326     LPWSTR pWidename;
327     HRESULT hr;
328     int strlength;
329
330     TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_a(pSrcFile),
331         pSrcRect, dwFilter, Colorkey, pSrcInfo);
332
333     if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
334
335     strlength = MultiByteToWideChar(CP_ACP, 0, pSrcFile, -1, NULL, 0);
336     pWidename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlength * sizeof(WCHAR));
337     MultiByteToWideChar(CP_ACP, 0, pSrcFile, -1, pWidename, strlength);
338
339     hr = D3DXLoadSurfaceFromFileW(pDestSurface, pDestPalette, pDestRect, pWidename, pSrcRect, dwFilter, Colorkey, pSrcInfo);
340     HeapFree(GetProcessHeap(), 0, pWidename);
341
342     return hr;
343 }
344
345 HRESULT WINAPI D3DXLoadSurfaceFromFileW(LPDIRECT3DSURFACE9 pDestSurface,
346                                         CONST PALETTEENTRY *pDestPalette,
347                                         CONST RECT *pDestRect,
348                                         LPCWSTR pSrcFile,
349                                         CONST RECT *pSrcRect,
350                                         DWORD Filter,
351                                         D3DCOLOR Colorkey,
352                                         D3DXIMAGE_INFO *pSrcInfo)
353 {
354     HRESULT hr;
355     DWORD dwSize;
356     LPVOID pBuffer;
357
358     TRACE("(%p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, debugstr_w(pSrcFile),
359         pSrcRect, Filter, Colorkey, pSrcInfo);
360
361     if( !pSrcFile || !pDestSurface ) return D3DERR_INVALIDCALL;
362
363     hr = map_view_of_file(pSrcFile, &pBuffer, &dwSize);
364     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
365
366     hr = D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, Filter, Colorkey, pSrcInfo);
367     UnmapViewOfFile(pBuffer);
368
369     return hr;
370 }
371
372 /************************************************************
373  * D3DXLoadSurfaceFromResource
374  */
375 HRESULT WINAPI D3DXLoadSurfaceFromResourceA(LPDIRECT3DSURFACE9 pDestSurface,
376                                             CONST PALETTEENTRY *pDestPalette,
377                                             CONST RECT *pDestRect,
378                                             HMODULE hSrcModule,
379                                             LPCSTR pResource,
380                                             CONST RECT *pSrcRect,
381                                             DWORD dwFilter,
382                                             D3DCOLOR Colorkey,
383                                             D3DXIMAGE_INFO *pSrcInfo)
384 {
385     HRSRC hResInfo;
386
387     TRACE("(%p, %p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, hSrcModule,
388         debugstr_a(pResource), pSrcRect, dwFilter, Colorkey, pSrcInfo);
389
390     if( !pDestSurface ) return D3DERR_INVALIDCALL;
391
392     hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_RCDATA);
393     if(hResInfo) {
394         LPVOID pBuffer;
395         HRESULT hr;
396         DWORD dwSize;
397
398         hr = load_resource_into_memory(hSrcModule, hResInfo, &pBuffer, &dwSize);
399         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
400         return D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
401     }
402
403     hResInfo = FindResourceA(hSrcModule, pResource, (LPCSTR)RT_BITMAP);
404     if(hResInfo) {
405         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
406         return E_NOTIMPL;
407     }
408     return D3DXERR_INVALIDDATA;
409 }
410
411 HRESULT WINAPI D3DXLoadSurfaceFromResourceW(LPDIRECT3DSURFACE9 pDestSurface,
412                                             CONST PALETTEENTRY *pDestPalette,
413                                             CONST RECT *pDestRect,
414                                             HMODULE hSrcModule,
415                                             LPCWSTR pResource,
416                                             CONST RECT *pSrcRect,
417                                             DWORD dwFilter,
418                                             D3DCOLOR Colorkey,
419                                             D3DXIMAGE_INFO *pSrcInfo)
420 {
421     HRSRC hResInfo;
422
423     TRACE("(%p, %p, %p, %p, %s, %p, %u, %#x, %p): relay\n", pDestSurface, pDestPalette, pDestRect, hSrcModule,
424         debugstr_w(pResource), pSrcRect, dwFilter, Colorkey, pSrcInfo);
425
426     if( !pDestSurface ) return D3DERR_INVALIDCALL;
427
428     hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_RCDATA);
429     if(hResInfo) {
430         LPVOID pBuffer;
431         HRESULT hr;
432         DWORD dwSize;
433
434         hr = load_resource_into_memory(hSrcModule, hResInfo, &pBuffer, &dwSize);
435         if(FAILED(hr)) return D3DXERR_INVALIDDATA;
436         return D3DXLoadSurfaceFromFileInMemory(pDestSurface, pDestPalette, pDestRect, pBuffer, dwSize, pSrcRect, dwFilter, Colorkey, pSrcInfo);
437     }
438
439     hResInfo = FindResourceW(hSrcModule, pResource, (LPCWSTR)RT_BITMAP);
440     if(hResInfo) {
441         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
442         return E_NOTIMPL;
443     }
444     return D3DXERR_INVALIDDATA;
445 }
446
447
448 /************************************************************
449  * copy_simple_data
450  *
451  * Copies the source buffer to the destination buffer, performing
452  * any necessary format conversion and color keying.
453  * Works only for ARGB formats with 1 - 4 bytes per pixel.
454  */
455 static void copy_simple_data(CONST BYTE *src,  UINT  srcpitch, POINT  srcsize, CONST PixelFormatDesc  *srcformat,
456                              CONST BYTE *dest, UINT destpitch, POINT destsize, CONST PixelFormatDesc *destformat,
457                              DWORD dwFilter)
458 {
459     DWORD srcshift[4], destshift[4];
460     DWORD srcmask[4], destmask[4];
461     BOOL process_channel[4];
462     DWORD channels[4];
463     DWORD channelmask = 0;
464
465     UINT minwidth, minheight;
466     BYTE *srcptr, *destptr;
467     UINT i, x, y;
468
469     ZeroMemory(channels, sizeof(channels));
470     ZeroMemory(process_channel, sizeof(process_channel));
471
472     for(i = 0;i < 4;i++) {
473         /* srcshift is used to extract the _relevant_ components */
474         srcshift[i]  =  srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0);
475
476         /* destshift is used to move the components to the correct position */
477         destshift[i] = destformat->shift[i] + max(destformat->bits[i] -  srcformat->bits[i], 0);
478
479         srcmask[i]  = ((1 <<  srcformat->bits[i]) - 1) <<  srcformat->shift[i];
480         destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i];
481
482         /* channelmask specifies bits which aren't used in the source format but in the destination one */
483         if(destformat->bits[i]) {
484             if(srcformat->bits[i]) process_channel[i] = TRUE;
485             else channelmask |= destmask[i];
486         }
487     }
488
489     minwidth  = (srcsize.x < destsize.x) ? srcsize.x : destsize.x;
490     minheight = (srcsize.y < destsize.y) ? srcsize.y : destsize.y;
491
492     for(y = 0;y < minheight;y++) {
493         srcptr  = (BYTE*)( src + y *  srcpitch);
494         destptr = (BYTE*)(dest + y * destpitch);
495         for(x = 0;x < minwidth;x++) {
496             /* extract source color components */
497             if(srcformat->type == FORMAT_ARGB) {
498                 const DWORD col = *(DWORD*)srcptr;
499                 for(i = 0;i < 4;i++)
500                     if(process_channel[i])
501                         channels[i] = (col & srcmask[i]) >> srcshift[i];
502             }
503
504             /* recombine the components */
505             if(destformat->type == FORMAT_ARGB) {
506                 DWORD* const pixel = (DWORD*)destptr;
507                 *pixel = 0;
508
509                 for(i = 0;i < 4;i++) {
510                     if(process_channel[i]) {
511                         /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */
512                         signed int shift;
513                         for(shift = destshift[i]; shift > destformat->shift[i]; shift -= srcformat->bits[i]) *pixel |= channels[i] << shift;
514                         *pixel |= (channels[i] >> (destformat->shift[i] - shift)) << destformat->shift[i];
515                     }
516                 }
517                 *pixel |= channelmask;   /* new channels are set to their maximal value */
518             }
519             srcptr  +=  srcformat->bytes_per_pixel;
520             destptr += destformat->bytes_per_pixel;
521         }
522     }
523 }
524
525 /************************************************************
526  * D3DXLoadSurfaceFromMemory
527  *
528  * Loads data from a given memory chunk into a surface,
529  * applying any of the specified filters.
530  *
531  * PARAMS
532  *   pDestSurface [I] pointer to the surface
533  *   pDestPalette [I] palette to use
534  *   pDestRect    [I] to be filled area of the surface
535  *   pSrcMemory   [I] pointer to the source data
536  *   SrcFormat    [I] format of the source pixel data
537  *   SrcPitch     [I] number of bytes in a row
538  *   pSrcPalette  [I] palette used in the source image
539  *   pSrcRect     [I] area of the source data to load
540  *   dwFilter     [I] filter to apply on stretching
541  *   Colorkey     [I] colorkey
542  *
543  * RETURNS
544  *   Success: D3D_OK, if we successfully load the pixel data into our surface or
545  *                    if pSrcMemory is NULL but the other parameters are valid
546  *   Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or
547  *                                if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN)
548  *            D3DXERR_INVALIDDATA, if we fail to lock pDestSurface
549  *            E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid
550  *
551  * NOTES
552  *   pSrcRect specifies the dimensions of the source data;
553  *   negative values for pSrcRect are allowed as we're only looking at the width and height anyway.
554  *
555  */
556 HRESULT WINAPI D3DXLoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSurface,
557                                          CONST PALETTEENTRY *pDestPalette,
558                                          CONST RECT *pDestRect,
559                                          LPCVOID pSrcMemory,
560                                          D3DFORMAT SrcFormat,
561                                          UINT SrcPitch,
562                                          CONST PALETTEENTRY *pSrcPalette,
563                                          CONST RECT *pSrcRect,
564                                          DWORD dwFilter,
565                                          D3DCOLOR Colorkey)
566 {
567     CONST PixelFormatDesc *srcformatdesc, *destformatdesc;
568     D3DSURFACE_DESC surfdesc;
569     D3DLOCKED_RECT lockrect;
570     POINT srcsize, destsize;
571     HRESULT hr;
572
573     TRACE("(%p, %p, %p, %p, %x, %u, %p, %p %u, %#x)\n", pDestSurface, pDestPalette, pDestRect, pSrcMemory,
574         SrcFormat, SrcPitch, pSrcPalette, pSrcRect, dwFilter, Colorkey);
575
576     if( !pDestSurface || !pSrcMemory || !pSrcRect ) return D3DERR_INVALIDCALL;
577     if(SrcFormat == D3DFMT_UNKNOWN || pSrcRect->left >= pSrcRect->right || pSrcRect->top >= pSrcRect->bottom) return E_FAIL;
578
579     if(dwFilter != D3DX_FILTER_NONE) return E_NOTIMPL;
580
581     IDirect3DSurface9_GetDesc(pDestSurface, &surfdesc);
582
583     srcformatdesc = get_format_info(SrcFormat);
584     destformatdesc = get_format_info(surfdesc.Format);
585     if( srcformatdesc->type == FORMAT_UNKNOWN ||  srcformatdesc->bytes_per_pixel > 4) return E_NOTIMPL;
586     if(destformatdesc->type == FORMAT_UNKNOWN || destformatdesc->bytes_per_pixel > 4) return E_NOTIMPL;
587
588     srcsize.x = pSrcRect->right - pSrcRect->left;
589     srcsize.y = pSrcRect->bottom - pSrcRect->top;
590     if( !pDestRect ) {
591         destsize.x = surfdesc.Width;
592         destsize.y = surfdesc.Height;
593     } else {
594         destsize.x = pDestRect->right - pDestRect->left;
595         destsize.y = pDestRect->bottom - pDestRect->top;
596     }
597
598     hr = IDirect3DSurface9_LockRect(pDestSurface, &lockrect, pDestRect, 0);
599     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
600
601     copy_simple_data((CONST BYTE*)pSrcMemory, SrcPitch, srcsize, srcformatdesc,
602                      (CONST BYTE*)lockrect.pBits, lockrect.Pitch, destsize, destformatdesc,
603                      dwFilter);
604
605     IDirect3DSurface9_UnlockRect(pDestSurface);
606     return D3D_OK;
607 }
608
609 /************************************************************
610  * D3DXLoadSurfaceFromSurface
611  *
612  * Copies the contents from one surface to another, performing any required
613  * format conversion, resizing or filtering.
614  *
615  * PARAMS
616  *   pDestSurface [I] pointer to the destination surface
617  *   pDestPalette [I] palette to use
618  *   pDestRect    [I] to be filled area of the surface
619  *   pSrcSurface  [I] pointer to the source surface
620  *   pSrcPalette  [I] palette used for the source surface
621  *   pSrcRect     [I] area of the source data to load
622  *   dwFilter     [I] filter to apply on resizing
623  *   Colorkey     [I] any ARGB value or 0 to disable color-keying
624  *
625  * RETURNS
626  *   Success: D3D_OK
627  *   Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
628  *            D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
629  *
630  */
631 HRESULT WINAPI D3DXLoadSurfaceFromSurface(LPDIRECT3DSURFACE9 pDestSurface,
632                                           CONST PALETTEENTRY *pDestPalette,
633                                           CONST RECT *pDestRect,
634                                           LPDIRECT3DSURFACE9 pSrcSurface,
635                                           CONST PALETTEENTRY *pSrcPalette,
636                                           CONST RECT *pSrcRect,
637                                           DWORD dwFilter,
638                                           D3DCOLOR Colorkey)
639 {
640     RECT rect;
641     D3DLOCKED_RECT lock;
642     D3DSURFACE_DESC SrcDesc;
643     HRESULT hr;
644
645     TRACE("(%p, %p, %p, %p, %p, %p, %u, %#x): relay\n", pDestSurface, pDestPalette, pDestRect,
646         pSrcSurface, pSrcPalette, pSrcRect, dwFilter, Colorkey);
647
648     if( !pDestSurface || !pSrcSurface ) return D3DERR_INVALIDCALL;
649
650     IDirect3DSurface9_GetDesc(pSrcSurface, &SrcDesc);
651
652     if( !pSrcRect ) SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height);
653     else rect = *pSrcRect;
654
655     hr = IDirect3DSurface9_LockRect(pSrcSurface, &lock, NULL, D3DLOCK_READONLY);
656     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
657
658     hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
659                                    lock.pBits, SrcDesc.Format, lock.Pitch,
660                                    pSrcPalette, &rect, dwFilter, Colorkey);
661
662     IDirect3DSurface9_UnlockRect(pSrcSurface);
663     return hr;
664 }