d3dx9: Fix an off by one error in point_filter_simple_data.
[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     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  * helper functions for D3DXLoadSurfaceFromMemory
450  */
451 struct argb_conversion_info
452 {
453     CONST PixelFormatDesc *srcformat;
454     CONST PixelFormatDesc *destformat;
455     DWORD srcshift[4], destshift[4];
456     DWORD srcmask[4], destmask[4];
457     BOOL process_channel[4];
458     DWORD channelmask;
459 };
460
461 static void init_argb_conversion_info(CONST PixelFormatDesc *srcformat, CONST PixelFormatDesc *destformat, struct argb_conversion_info *info)
462 {
463     UINT i;
464     ZeroMemory(info->process_channel, 4 * sizeof(BOOL));
465     info->channelmask = 0;
466
467     info->srcformat  =  srcformat;
468     info->destformat = destformat;
469
470     for(i = 0;i < 4;i++) {
471         /* srcshift is used to extract the _relevant_ components */
472         info->srcshift[i]  =  srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0);
473
474         /* destshift is used to move the components to the correct position */
475         info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] -  srcformat->bits[i], 0);
476
477         info->srcmask[i]  = ((1 <<  srcformat->bits[i]) - 1) <<  srcformat->shift[i];
478         info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i];
479
480         /* channelmask specifies bits which aren't used in the source format but in the destination one */
481         if(destformat->bits[i]) {
482             if(srcformat->bits[i]) info->process_channel[i] = TRUE;
483             else info->channelmask |= info->destmask[i];
484         }
485     }
486 }
487
488 /************************************************************
489  * get_relevant_argb_components
490  *
491  * Extracts the relevant components from the source color and
492  * drops the less significant bits if they aren't used by the destination format.
493  */
494 static void get_relevant_argb_components(CONST struct argb_conversion_info *info, CONST DWORD col, DWORD *out)
495 {
496     UINT i = 0;
497     for(;i < 4;i++)
498         if(info->process_channel[i])
499             out[i] = (col & info->srcmask[i]) >> info->srcshift[i];
500 }
501
502 /************************************************************
503  * make_argb_color
504  *
505  * Recombines the output of get_relevant_argb_components and converts
506  * it to the destination format.
507  */
508 static void make_argb_color(CONST struct argb_conversion_info *info, CONST DWORD *in, DWORD *out)
509 {
510     UINT i;
511     *out = 0;
512
513     for(i = 0;i < 4;i++) {
514         if(info->process_channel[i]) {
515             /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */
516             signed int shift;
517             for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) *out |= in[i] << shift;
518             *out |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i];
519         }
520     }
521     *out |= info->channelmask;   /* new channels are set to their maximal value */
522 }
523
524 /************************************************************
525  * copy_simple_data
526  *
527  * Copies the source buffer to the destination buffer, performing
528  * any necessary format conversion and color keying.
529  * Pixels outsize the source rect are blacked out.
530  * Works only for ARGB formats with 1 - 4 bytes per pixel.
531  */
532 static void copy_simple_data(CONST BYTE *src,  UINT  srcpitch, POINT  srcsize, CONST PixelFormatDesc  *srcformat,
533                              BYTE *dest, UINT destpitch, POINT destsize, CONST PixelFormatDesc *destformat)
534 {
535     struct argb_conversion_info conv_info;
536     DWORD channels[4];
537     UINT minwidth, minheight;
538     UINT x, y;
539
540     ZeroMemory(channels, sizeof(channels));
541     init_argb_conversion_info(srcformat, destformat, &conv_info);
542
543     minwidth  = (srcsize.x < destsize.x) ? srcsize.x : destsize.x;
544     minheight = (srcsize.y < destsize.y) ? srcsize.y : destsize.y;
545
546     for(y = 0;y < minheight;y++) {
547         const BYTE *srcptr = src + y *  srcpitch;
548         BYTE *destptr = dest + y * destpitch;
549         for(x = 0;x < minwidth;x++) {
550             /* extract source color components */
551             if(srcformat->type == FORMAT_ARGB) get_relevant_argb_components(&conv_info, *(const DWORD*)srcptr, channels);
552
553             /* recombine the components */
554             if(destformat->type == FORMAT_ARGB) make_argb_color(&conv_info, channels, (DWORD*)destptr);
555
556             srcptr  +=  srcformat->bytes_per_pixel;
557             destptr += destformat->bytes_per_pixel;
558         }
559
560         if(srcsize.x < destsize.x) /* black out remaining pixels */
561             ZeroMemory(destptr, destformat->bytes_per_pixel * (destsize.x - srcsize.x));
562     }
563     if(srcsize.y < destsize.y) /* black out remaining pixels */
564         ZeroMemory(dest + srcsize.y * destpitch, destpitch * (destsize.y - srcsize.y));
565 }
566
567 /************************************************************
568  * point_filter_simple_data
569  *
570  * Copies the source buffer to the destination buffer, performing
571  * any necessary format conversion, color keying and stretching
572  * using a point filter.
573  * Works only for ARGB formats with 1 - 4 bytes per pixel.
574  */
575 static void point_filter_simple_data(CONST BYTE *src,  UINT  srcpitch, POINT  srcsize, CONST PixelFormatDesc  *srcformat,
576                                      BYTE *dest, UINT destpitch, POINT destsize, CONST PixelFormatDesc *destformat)
577 {
578     struct argb_conversion_info conv_info;
579     DWORD channels[4];
580
581     UINT x, y;
582
583     ZeroMemory(channels, sizeof(channels));
584     init_argb_conversion_info(srcformat, destformat, &conv_info);
585
586     for(y = 0;y < destsize.y;y++) {
587         BYTE *destptr = dest + y * destpitch;
588         const BYTE *bufptr = src + srcpitch * (y * srcsize.y / destsize.y);
589
590         for(x = 0;x < destsize.x;x++) {
591             const BYTE *srcptr = bufptr + (x * srcsize.x / destsize.x) * srcformat->bytes_per_pixel;
592
593             /* extract source color components */
594             if(srcformat->type == FORMAT_ARGB) get_relevant_argb_components(&conv_info, *(const DWORD*)srcptr, channels);
595
596             /* recombine the components */
597             if(destformat->type == FORMAT_ARGB) make_argb_color(&conv_info, channels, (DWORD*)destptr);
598
599             destptr += destformat->bytes_per_pixel;
600         }
601     }
602 }
603
604 /************************************************************
605  * D3DXLoadSurfaceFromMemory
606  *
607  * Loads data from a given memory chunk into a surface,
608  * applying any of the specified filters.
609  *
610  * PARAMS
611  *   pDestSurface [I] pointer to the surface
612  *   pDestPalette [I] palette to use
613  *   pDestRect    [I] to be filled area of the surface
614  *   pSrcMemory   [I] pointer to the source data
615  *   SrcFormat    [I] format of the source pixel data
616  *   SrcPitch     [I] number of bytes in a row
617  *   pSrcPalette  [I] palette used in the source image
618  *   pSrcRect     [I] area of the source data to load
619  *   dwFilter     [I] filter to apply on stretching
620  *   Colorkey     [I] colorkey
621  *
622  * RETURNS
623  *   Success: D3D_OK, if we successfully load the pixel data into our surface or
624  *                    if pSrcMemory is NULL but the other parameters are valid
625  *   Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or
626  *                                if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or
627  *                                if DestRect is invalid
628  *            D3DXERR_INVALIDDATA, if we fail to lock pDestSurface
629  *            E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid
630  *
631  * NOTES
632  *   pSrcRect specifies the dimensions of the source data;
633  *   negative values for pSrcRect are allowed as we're only looking at the width and height anyway.
634  *
635  */
636 HRESULT WINAPI D3DXLoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSurface,
637                                          CONST PALETTEENTRY *pDestPalette,
638                                          CONST RECT *pDestRect,
639                                          LPCVOID pSrcMemory,
640                                          D3DFORMAT SrcFormat,
641                                          UINT SrcPitch,
642                                          CONST PALETTEENTRY *pSrcPalette,
643                                          CONST RECT *pSrcRect,
644                                          DWORD dwFilter,
645                                          D3DCOLOR Colorkey)
646 {
647     CONST PixelFormatDesc *srcformatdesc, *destformatdesc;
648     D3DSURFACE_DESC surfdesc;
649     D3DLOCKED_RECT lockrect;
650     POINT srcsize, destsize;
651     HRESULT hr;
652
653     TRACE("(%p, %p, %p, %p, %x, %u, %p, %p %u, %#x)\n", pDestSurface, pDestPalette, pDestRect, pSrcMemory,
654         SrcFormat, SrcPitch, pSrcPalette, pSrcRect, dwFilter, Colorkey);
655
656     if( !pDestSurface || !pSrcMemory || !pSrcRect ) return D3DERR_INVALIDCALL;
657     if(SrcFormat == D3DFMT_UNKNOWN || pSrcRect->left >= pSrcRect->right || pSrcRect->top >= pSrcRect->bottom) return E_FAIL;
658
659     if(dwFilter == D3DX_DEFAULT) dwFilter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
660
661     IDirect3DSurface9_GetDesc(pDestSurface, &surfdesc);
662
663     srcformatdesc = get_format_info(SrcFormat);
664     destformatdesc = get_format_info(surfdesc.Format);
665     if( srcformatdesc->type == FORMAT_UNKNOWN ||  srcformatdesc->bytes_per_pixel > 4) return E_NOTIMPL;
666     if(destformatdesc->type == FORMAT_UNKNOWN || destformatdesc->bytes_per_pixel > 4) return E_NOTIMPL;
667
668     srcsize.x = pSrcRect->right - pSrcRect->left;
669     srcsize.y = pSrcRect->bottom - pSrcRect->top;
670     if( !pDestRect ) {
671         destsize.x = surfdesc.Width;
672         destsize.y = surfdesc.Height;
673     } else {
674         if(pDestRect->left > pDestRect->right || pDestRect->right > surfdesc.Width) return D3DERR_INVALIDCALL;
675         if(pDestRect->top > pDestRect->bottom || pDestRect->bottom > surfdesc.Height) return D3DERR_INVALIDCALL;
676         if(pDestRect->left < 0 || pDestRect->top < 0) return D3DERR_INVALIDCALL;
677         destsize.x = pDestRect->right - pDestRect->left;
678         destsize.y = pDestRect->bottom - pDestRect->top;
679         if(destsize.x == 0 || destsize.y == 0) return D3D_OK;
680     }
681
682     hr = IDirect3DSurface9_LockRect(pDestSurface, &lockrect, pDestRect, 0);
683     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
684
685     if((dwFilter & 0xF) == D3DX_FILTER_NONE) {
686         copy_simple_data(pSrcMemory, SrcPitch, srcsize, srcformatdesc,
687                          lockrect.pBits, lockrect.Pitch, destsize, destformatdesc);
688     } else /*if((dwFilter & 0xF) == D3DX_FILTER_POINT) */ {
689         /* always apply a point filter until D3DX_FILTER_LINEAR, D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented */
690         point_filter_simple_data(pSrcMemory, SrcPitch, srcsize, srcformatdesc,
691                                  lockrect.pBits, lockrect.Pitch, destsize, destformatdesc);
692     }
693
694     IDirect3DSurface9_UnlockRect(pDestSurface);
695     return D3D_OK;
696 }
697
698 /************************************************************
699  * D3DXLoadSurfaceFromSurface
700  *
701  * Copies the contents from one surface to another, performing any required
702  * format conversion, resizing or filtering.
703  *
704  * PARAMS
705  *   pDestSurface [I] pointer to the destination surface
706  *   pDestPalette [I] palette to use
707  *   pDestRect    [I] to be filled area of the surface
708  *   pSrcSurface  [I] pointer to the source surface
709  *   pSrcPalette  [I] palette used for the source surface
710  *   pSrcRect     [I] area of the source data to load
711  *   dwFilter     [I] filter to apply on resizing
712  *   Colorkey     [I] any ARGB value or 0 to disable color-keying
713  *
714  * RETURNS
715  *   Success: D3D_OK
716  *   Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
717  *            D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
718  *
719  */
720 HRESULT WINAPI D3DXLoadSurfaceFromSurface(LPDIRECT3DSURFACE9 pDestSurface,
721                                           CONST PALETTEENTRY *pDestPalette,
722                                           CONST RECT *pDestRect,
723                                           LPDIRECT3DSURFACE9 pSrcSurface,
724                                           CONST PALETTEENTRY *pSrcPalette,
725                                           CONST RECT *pSrcRect,
726                                           DWORD dwFilter,
727                                           D3DCOLOR Colorkey)
728 {
729     RECT rect;
730     D3DLOCKED_RECT lock;
731     D3DSURFACE_DESC SrcDesc;
732     HRESULT hr;
733
734     TRACE("(%p, %p, %p, %p, %p, %p, %u, %#x): relay\n", pDestSurface, pDestPalette, pDestRect,
735         pSrcSurface, pSrcPalette, pSrcRect, dwFilter, Colorkey);
736
737     if( !pDestSurface || !pSrcSurface ) return D3DERR_INVALIDCALL;
738
739     IDirect3DSurface9_GetDesc(pSrcSurface, &SrcDesc);
740
741     if( !pSrcRect ) SetRect(&rect, 0, 0, SrcDesc.Width, SrcDesc.Height);
742     else rect = *pSrcRect;
743
744     hr = IDirect3DSurface9_LockRect(pSrcSurface, &lock, NULL, D3DLOCK_READONLY);
745     if(FAILED(hr)) return D3DXERR_INVALIDDATA;
746
747     hr = D3DXLoadSurfaceFromMemory(pDestSurface, pDestPalette, pDestRect,
748                                    lock.pBits, SrcDesc.Format, lock.Pitch,
749                                    pSrcPalette, &rect, dwFilter, Colorkey);
750
751     IDirect3DSurface9_UnlockRect(pSrcSurface);
752     return hr;
753 }