d3dx9/tests: Raise admitted error a bit in D3DXSHEvalSphericalLight tests.
[wine] / dlls / d3dx9_36 / texture.c
1 /*
2  * Copyright 2009 Tony Wasserka
3  * Copyright 2010 Christian Costa
4  * Copyright 2010 Owen Rudge for CodeWeavers
5  * Copyright 2010 Matteo Bruni for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "wine/unicode.h"
23 #include "wine/debug.h"
24 #include "d3dx9_36_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
27
28 /* Returns TRUE if num is a power of 2, FALSE if not, or if 0 */
29 static BOOL is_pow2(UINT num)
30 {
31     return !(num & (num - 1));
32 }
33
34 /* Returns the smallest power of 2 which is greater than or equal to num */
35 static UINT make_pow2(UINT num)
36 {
37     UINT result = 1;
38
39     /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */
40     if (num >= 0x80000000)
41         return 0x80000000;
42
43     while (result < num)
44         result <<= 1;
45
46     return result;
47 }
48
49 static HRESULT get_surface(D3DRESOURCETYPE type, struct IDirect3DBaseTexture9 *tex,
50         int face, UINT level, struct IDirect3DSurface9 **surf)
51 {
52     switch (type)
53     {
54         case D3DRTYPE_TEXTURE:
55             return IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) tex, level, surf);
56         case D3DRTYPE_CUBETEXTURE:
57             return IDirect3DCubeTexture9_GetCubeMapSurface((IDirect3DCubeTexture9*) tex, face, level, surf);
58         default:
59             ERR("Unexpected texture type\n");
60             return E_NOTIMPL;
61     }
62 }
63
64 HRESULT WINAPI D3DXFilterTexture(IDirect3DBaseTexture9 *texture,
65                                  const PALETTEENTRY *palette,
66                                  UINT srclevel,
67                                  DWORD filter)
68 {
69     UINT level;
70     HRESULT hr;
71     D3DRESOURCETYPE type;
72
73     TRACE("(%p, %p, %u, %#x)\n", texture, palette, srclevel, filter);
74
75     if (!texture)
76         return D3DERR_INVALIDCALL;
77
78     if ((filter & 0xFFFF) > D3DX_FILTER_BOX && filter != D3DX_DEFAULT)
79         return D3DERR_INVALIDCALL;
80
81     if (srclevel == D3DX_DEFAULT)
82         srclevel = 0;
83     else if (srclevel >= IDirect3DBaseTexture9_GetLevelCount(texture))
84         return D3DERR_INVALIDCALL;
85
86     switch (type = IDirect3DBaseTexture9_GetType(texture))
87     {
88         case D3DRTYPE_TEXTURE:
89         case D3DRTYPE_CUBETEXTURE:
90         {
91             IDirect3DSurface9 *topsurf, *mipsurf;
92             D3DSURFACE_DESC desc;
93             int i, numfaces;
94
95             if (type == D3DRTYPE_TEXTURE)
96             {
97                 numfaces = 1;
98                 IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
99             }
100             else
101             {
102                 numfaces = 6;
103                 IDirect3DCubeTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
104             }
105
106             if (filter == D3DX_DEFAULT)
107             {
108                 if (is_pow2(desc.Width) && is_pow2(desc.Height))
109                     filter = D3DX_FILTER_BOX;
110                 else
111                     filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER;
112             }
113
114             for (i = 0; i < numfaces; i++)
115             {
116                 level = srclevel + 1;
117                 hr = get_surface(type, texture, i, srclevel, &topsurf);
118
119                 if (FAILED(hr))
120                     return D3DERR_INVALIDCALL;
121
122                 while (get_surface(type, texture, i, level, &mipsurf) == D3D_OK)
123                 {
124                     hr = D3DXLoadSurfaceFromSurface(mipsurf, palette, NULL, topsurf, palette, NULL, filter, 0);
125                     IDirect3DSurface9_Release(topsurf);
126                     topsurf = mipsurf;
127
128                     if (FAILED(hr))
129                         break;
130
131                     level++;
132                 }
133
134                 IDirect3DSurface9_Release(topsurf);
135                 if (FAILED(hr))
136                     return hr;
137             }
138
139             return D3D_OK;
140         }
141
142         case D3DRTYPE_VOLUMETEXTURE:
143         {
144             D3DVOLUME_DESC desc;
145             int level, level_count;
146             IDirect3DVolume9 *top_volume, *mip_volume;
147             IDirect3DVolumeTexture9 *volume_texture = (IDirect3DVolumeTexture9*) texture;
148
149             IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, srclevel, &desc);
150
151             if (filter == D3DX_DEFAULT)
152             {
153                 if (is_pow2(desc.Width) && is_pow2(desc.Height) && is_pow2(desc.Depth))
154                     filter = D3DX_FILTER_BOX;
155                 else
156                     filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER;
157             }
158
159             hr = IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, srclevel, &top_volume);
160             if (FAILED(hr))
161                 return hr;
162
163             level_count = IDirect3DVolumeTexture9_GetLevelCount(volume_texture);
164             for (level = srclevel + 1; level < level_count; level++)
165             {
166                 IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, level, &mip_volume);
167                 hr = D3DXLoadVolumeFromVolume(mip_volume, palette, NULL, top_volume, palette, NULL, filter, 0);
168                 IDirect3DVolume9_Release(top_volume);
169                 top_volume = mip_volume;
170
171                 if (FAILED(hr))
172                     break;
173             }
174
175             IDirect3DVolume9_Release(top_volume);
176             if (FAILED(hr))
177                 return hr;
178
179             return D3D_OK;
180         }
181
182         default:
183             return D3DERR_INVALIDCALL;
184     }
185 }
186
187 HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height,
188         UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
189 {
190     UINT w = (width && *width) ? *width : 1;
191     UINT h = (height && *height) ? *height : 1;
192     D3DCAPS9 caps;
193     D3DDEVICE_CREATION_PARAMETERS params;
194     IDirect3D9 *d3d = NULL;
195     D3DDISPLAYMODE mode;
196     HRESULT hr;
197     D3DFORMAT usedformat = D3DFMT_UNKNOWN;
198
199     TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool);
200
201     if (!device)
202         return D3DERR_INVALIDCALL;
203
204     /* usage */
205     if (usage == D3DX_DEFAULT)
206         usage = 0;
207     if (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES))
208         return D3DERR_INVALIDCALL;
209
210     /* pool */
211     if ((pool != D3DPOOL_DEFAULT) && (pool != D3DPOOL_MANAGED) && (pool != D3DPOOL_SYSTEMMEM) && (pool != D3DPOOL_SCRATCH))
212         return D3DERR_INVALIDCALL;
213
214     /* width and height */
215     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
216         return D3DERR_INVALIDCALL;
217
218     /* 256 x 256 default width/height */
219     if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT))
220         w = h = 256;
221     else if (w == D3DX_DEFAULT)
222         w = (height ? h : 256);
223     else if (h == D3DX_DEFAULT)
224         h = (width ? w : 256);
225
226     /* ensure width/height is power of 2 */
227     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w)))
228         w = make_pow2(w);
229
230     if (w > caps.MaxTextureWidth)
231         w = caps.MaxTextureWidth;
232
233     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h)))
234         h = make_pow2(h);
235
236     if (h > caps.MaxTextureHeight)
237         h = caps.MaxTextureHeight;
238
239     /* texture must be square? */
240     if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
241     {
242         if (w > h)
243             h = w;
244         else
245             w = h;
246     }
247
248     if (width)
249         *width = w;
250
251     if (height)
252         *height = h;
253
254     /* miplevels */
255     if (miplevels && (usage & D3DUSAGE_AUTOGENMIPMAP))
256     {
257         if (*miplevels > 1)
258             *miplevels = 0;
259     }
260     else if (miplevels)
261     {
262         UINT max_mipmaps = 1;
263
264         if (!width && !height)
265             max_mipmaps = 9;    /* number of mipmaps in a 256x256 texture */
266         else
267         {
268             UINT max_dimen = max(w, h);
269
270             while (max_dimen > 1)
271             {
272                 max_dimen >>= 1;
273                 max_mipmaps++;
274             }
275         }
276
277         if (*miplevels == 0 || *miplevels > max_mipmaps)
278             *miplevels = max_mipmaps;
279     }
280
281     /* format */
282     if (format)
283     {
284         TRACE("Requested format %x\n", *format);
285         usedformat = *format;
286     }
287
288     hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
289
290     if (FAILED(hr))
291         goto cleanup;
292
293     hr = IDirect3DDevice9_GetCreationParameters(device, &params);
294
295     if (FAILED(hr))
296         goto cleanup;
297
298     hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
299
300     if (FAILED(hr))
301         goto cleanup;
302
303     if ((usedformat == D3DFMT_UNKNOWN) || (usedformat == D3DX_DEFAULT))
304         usedformat = D3DFMT_A8R8G8B8;
305
306     hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format,
307         usage, D3DRTYPE_TEXTURE, usedformat);
308
309     if (FAILED(hr))
310     {
311         /* Heuristic to choose the fallback format */
312         const struct pixel_format_desc *fmt = get_format_info(usedformat);
313         BOOL allow_24bits;
314         int bestscore = INT_MIN, i = 0, j;
315         unsigned int channels;
316         const struct pixel_format_desc *curfmt;
317
318         if (!fmt)
319         {
320             FIXME("Pixel format %x not handled\n", usedformat);
321             goto cleanup;
322         }
323
324         allow_24bits = fmt->bytes_per_pixel == 3;
325         channels = (fmt->bits[0] ? 1 : 0) + (fmt->bits[1] ? 1 : 0)
326             + (fmt->bits[2] ? 1 : 0) + (fmt->bits[3] ? 1 : 0);
327         usedformat = D3DFMT_UNKNOWN;
328
329         while ((curfmt = get_format_info_idx(i)))
330         {
331             unsigned int curchannels = (curfmt->bits[0] ? 1 : 0) + (curfmt->bits[1] ? 1 : 0)
332                 + (curfmt->bits[2] ? 1 : 0) + (curfmt->bits[3] ? 1 : 0);
333             int score;
334
335             i++;
336
337             if (curchannels < channels)
338                 continue;
339             if (curfmt->bytes_per_pixel == 3 && !allow_24bits)
340                 continue;
341
342             hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
343                 mode.Format, usage, D3DRTYPE_TEXTURE, curfmt->format);
344             if (FAILED(hr))
345                 continue;
346
347             /* This format can be used, let's evaluate it.
348                Weights chosen quite arbitrarily... */
349             score = 16 - 4 * (curchannels - channels);
350
351             for (j = 0; j < 4; j++)
352             {
353                 int diff = curfmt->bits[j] - fmt->bits[j];
354                 score += 16 - (diff < 0 ? -diff * 4 : diff);
355             }
356
357             if (score > bestscore)
358             {
359                 bestscore = score;
360                 usedformat = curfmt->format;
361             }
362         }
363         hr = D3D_OK;
364     }
365
366 cleanup:
367
368     if (d3d)
369         IDirect3D9_Release(d3d);
370
371     if (FAILED(hr))
372         return hr;
373
374     if (usedformat == D3DFMT_UNKNOWN)
375     {
376         WARN("Couldn't find a suitable pixel format\n");
377         return D3DERR_NOTAVAILABLE;
378     }
379
380     TRACE("Format chosen: %x\n", usedformat);
381     if (format)
382         *format = usedformat;
383
384     return D3D_OK;
385 }
386
387 HRESULT WINAPI D3DXCheckCubeTextureRequirements(struct IDirect3DDevice9 *device, UINT *size,
388         UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
389 {
390     D3DCAPS9 caps;
391     UINT s = (size && *size) ? *size : 256;
392     HRESULT hr;
393
394     TRACE("(%p, %p, %p, %u, %p, %u)\n", device, size, miplevels, usage, format, pool);
395
396     if (s == D3DX_DEFAULT)
397         s = 256;
398
399     if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
400         return D3DERR_INVALIDCALL;
401
402     if (!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
403         return D3DERR_NOTAVAILABLE;
404
405     /* ensure width/height is power of 2 */
406     if ((caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && (!is_pow2(s)))
407         s = make_pow2(s);
408
409     hr = D3DXCheckTextureRequirements(device, &s, &s, miplevels, usage, format, pool);
410
411     if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP))
412     {
413         if(miplevels)
414             *miplevels = 1;
415     }
416
417     if (size)
418         *size = s;
419
420     return hr;
421 }
422
423 HRESULT WINAPI D3DXCheckVolumeTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height,
424         UINT *depth, UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
425 {
426     D3DCAPS9 caps;
427     UINT w = width ? *width : D3DX_DEFAULT;
428     UINT h = height ? *height : D3DX_DEFAULT;
429     UINT d = (depth && *depth) ? *depth : 1;
430     HRESULT hr;
431
432     TRACE("(%p, %p, %p, %p, %p, %u, %p, %u)\n", device, width, height, depth, miplevels,
433           usage, format, pool);
434
435     if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
436         return D3DERR_INVALIDCALL;
437
438     if (!(caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP))
439         return D3DERR_NOTAVAILABLE;
440
441     hr = D3DXCheckTextureRequirements(device, &w, &h, NULL, usage, format, pool);
442     if (d == D3DX_DEFAULT)
443         d = 1;
444
445     /* ensure width/height is power of 2 */
446     if ((caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) &&
447         (!is_pow2(w) || !is_pow2(h) || !is_pow2(d)))
448     {
449         w = make_pow2(w);
450         h = make_pow2(h);
451         d = make_pow2(d);
452     }
453
454     if (w > caps.MaxVolumeExtent)
455         w = caps.MaxVolumeExtent;
456     if (h > caps.MaxVolumeExtent)
457         h = caps.MaxVolumeExtent;
458     if (d > caps.MaxVolumeExtent)
459         d = caps.MaxVolumeExtent;
460
461     if (miplevels)
462     {
463         if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP))
464             *miplevels = 1;
465         else if ((usage & D3DUSAGE_AUTOGENMIPMAP))
466         {
467             if (*miplevels > 1)
468                 *miplevels = 0;
469         }
470         else
471         {
472             UINT max_mipmaps = 1;
473             UINT max_dimen = max(max(w, h), d);
474
475             while (max_dimen > 1)
476             {
477                 max_dimen >>= 1;
478                 max_mipmaps++;
479             }
480
481             if (*miplevels == 0 || *miplevels > max_mipmaps)
482                 *miplevels = max_mipmaps;
483         }
484     }
485
486     if (width)
487         *width = w;
488     if (height)
489         *height = h;
490     if (depth)
491         *depth = d;
492
493     return hr;
494 }
495
496 HRESULT WINAPI D3DXCreateTexture(struct IDirect3DDevice9 *device, UINT width, UINT height,
497         UINT miplevels, DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DTexture9 **texture)
498 {
499     HRESULT hr;
500
501     TRACE("device %p, width %u, height %u, miplevels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
502             device, width, height, miplevels, usage, format, pool, texture);
503
504     if (!device || !texture)
505         return D3DERR_INVALIDCALL;
506
507     if (FAILED(hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool)))
508         return hr;
509
510     return IDirect3DDevice9_CreateTexture(device, width, height, miplevels, usage, format, pool, texture, NULL);
511 }
512
513 HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *device, const void *srcdata,
514         UINT srcdatasize, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
515         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
516         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
517 {
518     IDirect3DTexture9 **texptr;
519     IDirect3DTexture9 *buftex;
520     IDirect3DSurface9 *surface;
521     BOOL file_width = FALSE, file_height = FALSE;
522     BOOL file_format = FALSE, file_miplevels = FALSE;
523     BOOL dynamic_texture;
524     D3DXIMAGE_INFO imginfo;
525     UINT loaded_miplevels;
526     D3DCAPS9 caps;
527     HRESULT hr;
528
529     TRACE("(%p, %p, %u, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p)\n", device, srcdata, srcdatasize, width,
530         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
531
532     /* check for invalid parameters */
533     if (!device || !texture || !srcdata || !srcdatasize)
534         return D3DERR_INVALIDCALL;
535
536     hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo);
537
538     if (FAILED(hr))
539     {
540         *texture = NULL;
541         return hr;
542     }
543
544     /* handle default values */
545     if (width == 0 || width == D3DX_DEFAULT_NONPOW2)
546         width = imginfo.Width;
547
548     if (height == 0 || height == D3DX_DEFAULT_NONPOW2)
549         height = imginfo.Height;
550
551     if (width == D3DX_DEFAULT)
552         width = make_pow2(imginfo.Width);
553
554     if (height == D3DX_DEFAULT)
555         height = make_pow2(imginfo.Height);
556
557     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
558         format = imginfo.Format;
559
560     if (width == D3DX_FROM_FILE)
561     {
562         file_width = TRUE;
563         width = imginfo.Width;
564     }
565
566     if (height == D3DX_FROM_FILE)
567     {
568         file_height = TRUE;
569         height = imginfo.Height;
570     }
571
572     if (format == D3DFMT_FROM_FILE)
573     {
574         file_format = TRUE;
575         format = imginfo.Format;
576     }
577
578     if (miplevels == D3DX_FROM_FILE)
579     {
580         file_miplevels = TRUE;
581         miplevels = imginfo.MipLevels;
582     }
583
584     /* fix texture creation parameters */
585     hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
586
587     if (FAILED(hr))
588     {
589         *texture = NULL;
590         return hr;
591     }
592
593     if (imginfo.MipLevels < miplevels && (D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5))
594     {
595         FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet\n");
596         miplevels = imginfo.MipLevels;
597     }
598
599     if (((file_width) && (width != imginfo.Width))    ||
600         ((file_height) && (height != imginfo.Height)) ||
601         ((file_format) && (format != imginfo.Format)) ||
602         ((file_miplevels) && (miplevels != imginfo.MipLevels)))
603     {
604         return D3DERR_NOTAVAILABLE;
605     }
606
607     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
608         return D3DERR_INVALIDCALL;
609
610     /* Create the to-be-filled texture */
611     dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
612     if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
613     {
614         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
615         texptr = &buftex;
616     }
617     else
618     {
619         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
620         texptr = texture;
621     }
622
623     if (FAILED(hr))
624     {
625         *texture = NULL;
626         return hr;
627     }
628
629     /* Load the file */
630     if (imginfo.ImageFileFormat != D3DXIFF_DDS)
631     {
632         IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface);
633         hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL);
634         IDirect3DSurface9_Release(surface);
635     }
636     else
637     {
638         hr = load_texture_from_dds(*texptr, srcdata, palette, filter, colorkey, &imginfo);
639     }
640
641     if (FAILED(hr))
642     {
643         IDirect3DTexture9_Release(*texptr);
644         *texture = NULL;
645         return hr;
646     }
647
648     loaded_miplevels = min(IDirect3DTexture9_GetLevelCount(*texptr), imginfo.MipLevels);
649     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, loaded_miplevels - 1, mipfilter);
650
651     if (FAILED(hr))
652     {
653         IDirect3DTexture9_Release(*texptr);
654         *texture = NULL;
655         return hr;
656     }
657
658     /* Move the data to the actual texture if necessary */
659     if (texptr == &buftex)
660     {
661         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
662
663         if (FAILED(hr))
664         {
665             IDirect3DTexture9_Release(buftex);
666             *texture = NULL;
667             return hr;
668         }
669
670         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)buftex, (IDirect3DBaseTexture9*)(*texture));
671         IDirect3DTexture9_Release(buftex);
672     }
673
674     if (srcinfo)
675         *srcinfo = imginfo;
676
677     return D3D_OK;
678 }
679
680 HRESULT WINAPI D3DXCreateTextureFromFileInMemory(struct IDirect3DDevice9 *device,
681         const void *srcdata, UINT srcdatasize, struct IDirect3DTexture9 **texture)
682 {
683     TRACE("(%p, %p, %d, %p)\n", device, srcdata, srcdatasize, texture);
684
685     return D3DXCreateTextureFromFileInMemoryEx(device, srcdata, srcdatasize, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
686                                                D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
687 }
688
689 HRESULT WINAPI D3DXCreateTextureFromFileExW(struct IDirect3DDevice9 *device, const WCHAR *srcfile,
690         UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
691         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
692         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
693 {
694     HRESULT hr;
695     DWORD size;
696     LPVOID buffer;
697
698     TRACE("(%p, %s, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n",
699             device, debugstr_w(srcfile), width, height, miplevels, usage, format, pool, filter,
700             mipfilter, colorkey, srcinfo, palette, texture);
701
702     if (!srcfile)
703         return D3DERR_INVALIDCALL;
704
705     hr = map_view_of_file(srcfile, &buffer, &size);
706     if (FAILED(hr))
707         return D3DXERR_INVALIDDATA;
708
709     hr = D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width, height, miplevels, usage, format, pool,
710         filter, mipfilter, colorkey, srcinfo, palette, texture);
711
712     UnmapViewOfFile(buffer);
713
714     return hr;
715 }
716
717 HRESULT WINAPI D3DXCreateTextureFromFileExA(struct IDirect3DDevice9 *device, const char *srcfile,
718         UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
719         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
720         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
721 {
722     LPWSTR widename;
723     HRESULT hr;
724     DWORD len;
725
726     TRACE("(%p, %s, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n",
727             device, debugstr_a(srcfile), width, height, miplevels, usage, format, pool, filter,
728             mipfilter, colorkey, srcinfo, palette, texture);
729
730     if (!device || !srcfile || !texture)
731         return D3DERR_INVALIDCALL;
732
733     len = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
734     widename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*widename));
735     MultiByteToWideChar(CP_ACP, 0, srcfile, -1, widename, len);
736
737     hr = D3DXCreateTextureFromFileExW(device, widename, width, height, miplevels,
738                                       usage, format, pool, filter, mipfilter,
739                                       colorkey, srcinfo, palette, texture);
740
741     HeapFree(GetProcessHeap(), 0, widename);
742     return hr;
743 }
744
745 HRESULT WINAPI D3DXCreateTextureFromFileA(struct IDirect3DDevice9 *device,
746         const char *srcfile, struct IDirect3DTexture9 **texture)
747 {
748     TRACE("(%p, %s, %p)\n", device, debugstr_a(srcfile), texture);
749
750     return D3DXCreateTextureFromFileExA(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
751                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
752 }
753
754 HRESULT WINAPI D3DXCreateTextureFromFileW(struct IDirect3DDevice9 *device,
755         const WCHAR *srcfile, struct IDirect3DTexture9 **texture)
756 {
757     TRACE("(%p, %s, %p)\n", device, debugstr_w(srcfile), texture);
758
759     return D3DXCreateTextureFromFileExW(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
760                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
761 }
762
763
764 HRESULT WINAPI D3DXCreateTextureFromResourceA(struct IDirect3DDevice9 *device,
765         HMODULE srcmodule, const char *resource, struct IDirect3DTexture9 **texture)
766 {
767     TRACE("(%p, %s): relay\n", srcmodule, debugstr_a(resource));
768
769     return D3DXCreateTextureFromResourceExA(device, srcmodule, resource, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
770                                             D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
771 }
772
773 HRESULT WINAPI D3DXCreateTextureFromResourceW(struct IDirect3DDevice9 *device,
774         HMODULE srcmodule, const WCHAR *resource, struct IDirect3DTexture9 **texture)
775 {
776     TRACE("(%p, %s): relay\n", srcmodule, debugstr_w(resource));
777
778     return D3DXCreateTextureFromResourceExW(device, srcmodule, resource, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
779                                             D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
780 }
781
782 HRESULT WINAPI D3DXCreateTextureFromResourceExA(struct IDirect3DDevice9 *device, HMODULE srcmodule,
783         const char *resource, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
784         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
785         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
786 {
787     HRSRC resinfo;
788
789     TRACE("(%p, %s): relay\n", srcmodule, debugstr_a(resource));
790
791     if (!device || !texture)
792         return D3DERR_INVALIDCALL;
793
794     resinfo = FindResourceA(srcmodule, resource, (const char *)RT_RCDATA);
795     if (!resinfo) /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */
796         resinfo = FindResourceA(srcmodule, resource, (const char *)RT_BITMAP);
797
798     if (resinfo)
799     {
800         LPVOID buffer;
801         HRESULT hr;
802         DWORD size;
803
804         hr = load_resource_into_memory(srcmodule, resinfo, &buffer, &size);
805
806         if (FAILED(hr))
807             return D3DXERR_INVALIDDATA;
808
809         return D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width,
810                                                    height, miplevels, usage, format,
811                                                    pool, filter, mipfilter, colorkey,
812                                                    srcinfo, palette, texture);
813     }
814
815     return D3DXERR_INVALIDDATA;
816 }
817
818 HRESULT WINAPI D3DXCreateTextureFromResourceExW(struct IDirect3DDevice9 *device, HMODULE srcmodule,
819         const WCHAR *resource, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
820         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
821         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
822 {
823     HRSRC resinfo;
824
825     TRACE("(%p, %s): relay\n", srcmodule, debugstr_w(resource));
826
827     if (!device || !texture)
828         return D3DERR_INVALIDCALL;
829
830     resinfo = FindResourceW(srcmodule, resource, (const WCHAR *)RT_RCDATA);
831     if (!resinfo) /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */
832         resinfo = FindResourceW(srcmodule, resource, (const WCHAR *)RT_BITMAP);
833
834     if (resinfo)
835     {
836         LPVOID buffer;
837         HRESULT hr;
838         DWORD size;
839
840         hr = load_resource_into_memory(srcmodule, resinfo, &buffer, &size);
841
842         if (FAILED(hr))
843             return D3DXERR_INVALIDDATA;
844
845         return D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width,
846                                                    height, miplevels, usage, format,
847                                                    pool, filter, mipfilter, colorkey,
848                                                    srcinfo, palette, texture);
849     }
850
851     return D3DXERR_INVALIDDATA;
852 }
853
854 HRESULT WINAPI D3DXCreateCubeTexture(struct IDirect3DDevice9 *device, UINT size, UINT miplevels,
855         DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DCubeTexture9 **texture)
856 {
857     HRESULT hr;
858
859     TRACE("(%p, %u, %u, %#x, %#x, %#x, %p)\n", device, size, miplevels, usage, format,
860         pool, texture);
861
862     if (!device || !texture)
863         return D3DERR_INVALIDCALL;
864
865     hr = D3DXCheckCubeTextureRequirements(device, &size, &miplevels, usage, &format, pool);
866
867     if (FAILED(hr))
868     {
869         TRACE("D3DXCheckCubeTextureRequirements failed\n");
870         return hr;
871     }
872
873     return IDirect3DDevice9_CreateCubeTexture(device, size, miplevels, usage, format, pool, texture, NULL);
874 }
875
876 HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemory(struct IDirect3DDevice9 *device,
877         const void *data, UINT datasize, struct IDirect3DCubeTexture9 **texture)
878 {
879     TRACE("(%p, %p, %u, %p)\n", device, data, datasize, texture);
880
881     return D3DXCreateCubeTextureFromFileInMemoryEx(device, data, datasize, D3DX_DEFAULT, D3DX_DEFAULT,
882         0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
883 }
884
885 HRESULT WINAPI D3DXCreateVolumeTexture(struct IDirect3DDevice9 *device, UINT width, UINT height, UINT depth,
886         UINT miplevels, DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DVolumeTexture9 **texture)
887 {
888     HRESULT hr;
889
890     TRACE("(%p, %u, %u, %u, %u, %#x, %#x, %#x, %p)\n", device, width, height, depth,
891           miplevels, usage, format, pool, texture);
892
893     if (!device || !texture)
894         return D3DERR_INVALIDCALL;
895
896     hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth,
897                                             &miplevels, usage, &format, pool);
898
899     if (FAILED(hr))
900     {
901         TRACE("D3DXCheckVolumeTextureRequirements failed\n");
902         return hr;
903     }
904
905     return IDirect3DDevice9_CreateVolumeTexture(device, width, height, depth, miplevels,
906                                                 usage, format, pool, texture, NULL);
907 }
908
909 HRESULT WINAPI D3DXCreateVolumeTextureFromFileA(IDirect3DDevice9 *device,
910                                                 const char *filename,
911                                                 IDirect3DVolumeTexture9 **volume_texture)
912 {
913     int len;
914     HRESULT hr;
915     void *data;
916     DWORD data_size;
917     WCHAR *filenameW;
918
919     TRACE("(%p, %s, %p): relay\n",
920             device, debugstr_a(filename), volume_texture);
921
922     if (!filename) return D3DERR_INVALIDCALL;
923
924     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
925     filenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
926     if (!filenameW) return E_OUTOFMEMORY;
927     MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, len);
928
929     hr = map_view_of_file(filenameW, &data, &data_size);
930     HeapFree(GetProcessHeap(), 0, filenameW);
931     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
932
933     hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
934             D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, volume_texture);
935
936     UnmapViewOfFile(data);
937     return hr;
938 }
939
940 HRESULT WINAPI D3DXCreateVolumeTextureFromFileW(IDirect3DDevice9 *device,
941                                                 const WCHAR *filename,
942                                                 IDirect3DVolumeTexture9 **volume_texture)
943 {
944     HRESULT hr;
945     void *data;
946     DWORD data_size;
947
948     TRACE("(%p, %s, %p): relay\n",
949             device, debugstr_w(filename), volume_texture);
950
951     if (!filename) return D3DERR_INVALIDCALL;
952
953     hr = map_view_of_file(filename, &data, &data_size);
954     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
955
956     hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
957             D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, volume_texture);
958
959     UnmapViewOfFile(data);
960     return hr;
961 }
962
963 HRESULT WINAPI D3DXCreateVolumeTextureFromFileExA(IDirect3DDevice9 *device,
964                                                   const char *filename,
965                                                   UINT width,
966                                                   UINT height,
967                                                   UINT depth,
968                                                   UINT mip_levels,
969                                                   DWORD usage,
970                                                   D3DFORMAT format,
971                                                   D3DPOOL pool,
972                                                   DWORD filter,
973                                                   DWORD mip_filter,
974                                                   D3DCOLOR color_key,
975                                                   D3DXIMAGE_INFO *src_info,
976                                                   PALETTEENTRY *palette,
977                                                   IDirect3DVolumeTexture9 **volume_texture)
978 {
979     int len;
980     HRESULT hr;
981     WCHAR *filenameW;
982     void *data;
983     DWORD data_size;
984
985     TRACE("(%p, %s, %u, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n",
986             device, debugstr_a(filename), width, height, depth, mip_levels,
987             usage, format, pool, filter, mip_filter, color_key, src_info,
988             palette, volume_texture);
989
990     if (!filename) return D3DERR_INVALIDCALL;
991
992     len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
993     filenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
994     if (!filenameW) return E_OUTOFMEMORY;
995     MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, len);
996
997     hr = map_view_of_file(filenameW, &data, &data_size);
998     HeapFree(GetProcessHeap(), 0, filenameW);
999     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
1000
1001     hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, width, height, depth,
1002             mip_levels, usage, format, pool, filter, mip_filter, color_key, src_info, palette,
1003             volume_texture);
1004
1005     UnmapViewOfFile(data);
1006     return hr;
1007 }
1008
1009 HRESULT WINAPI D3DXCreateVolumeTextureFromFileExW(IDirect3DDevice9 *device,
1010                                                   const WCHAR *filename,
1011                                                   UINT width,
1012                                                   UINT height,
1013                                                   UINT depth,
1014                                                   UINT mip_levels,
1015                                                   DWORD usage,
1016                                                   D3DFORMAT format,
1017                                                   D3DPOOL pool,
1018                                                   DWORD filter,
1019                                                   DWORD mip_filter,
1020                                                   D3DCOLOR color_key,
1021                                                   D3DXIMAGE_INFO *src_info,
1022                                                   PALETTEENTRY *palette,
1023                                                   IDirect3DVolumeTexture9 **volume_texture)
1024 {
1025     HRESULT hr;
1026     void *data;
1027     DWORD data_size;
1028
1029     TRACE("(%p, %s, %u, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n",
1030             device, debugstr_w(filename), width, height, depth, mip_levels,
1031             usage, format, pool, filter, mip_filter, color_key, src_info,
1032             palette, volume_texture);
1033
1034     if (!filename) return D3DERR_INVALIDCALL;
1035
1036     hr = map_view_of_file(filename, &data, &data_size);
1037     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
1038
1039     hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, width, height, depth,
1040             mip_levels, usage, format, pool, filter, mip_filter, color_key, src_info, palette,
1041             volume_texture);
1042
1043     UnmapViewOfFile(data);
1044     return hr;
1045 }
1046
1047 HRESULT WINAPI D3DXCreateVolumeTextureFromFileInMemory(IDirect3DDevice9 *device,
1048                                                        const void *data,
1049                                                        UINT data_size,
1050                                                        IDirect3DVolumeTexture9 **volume_texture)
1051 {
1052     TRACE("(%p, %p, %u, %p): relay\n", device, data, data_size, volume_texture);
1053
1054     return D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT,
1055         D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,
1056         0, NULL, NULL, volume_texture);
1057 }
1058
1059 HRESULT WINAPI D3DXCreateVolumeTextureFromFileInMemoryEx(IDirect3DDevice9 *device,
1060                                                          const void *data,
1061                                                          UINT data_size,
1062                                                          UINT width,
1063                                                          UINT height,
1064                                                          UINT depth,
1065                                                          UINT mip_levels,
1066                                                          DWORD usage,
1067                                                          D3DFORMAT format,
1068                                                          D3DPOOL pool,
1069                                                          DWORD filter,
1070                                                          DWORD mip_filter,
1071                                                          D3DCOLOR color_key,
1072                                                          D3DXIMAGE_INFO *info,
1073                                                          PALETTEENTRY *palette,
1074                                                          IDirect3DVolumeTexture9 **volume_texture)
1075 {
1076     HRESULT hr;
1077     D3DCAPS9 caps;
1078     D3DXIMAGE_INFO image_info;
1079     BOOL dynamic_texture;
1080     BOOL file_width = FALSE;
1081     BOOL file_height = FALSE;
1082     BOOL file_depth = FALSE;
1083     BOOL file_format = FALSE;
1084     BOOL file_mip_levels = FALSE;
1085     IDirect3DVolumeTexture9 *tex, *buftex;
1086
1087     TRACE("(%p, %p, %u, %u, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p)\n",
1088             device, data, data_size, width, height, depth, mip_levels, usage, format, pool,
1089             filter, mip_filter, color_key, info, palette, volume_texture);
1090
1091     if (!device || !data || !data_size || !volume_texture)
1092         return D3DERR_INVALIDCALL;
1093
1094     hr = D3DXGetImageInfoFromFileInMemory(data, data_size, &image_info);
1095     if (FAILED(hr)) return hr;
1096
1097     if (image_info.ImageFileFormat != D3DXIFF_DDS)
1098         return D3DXERR_INVALIDDATA;
1099
1100     if (width == 0 || width == D3DX_DEFAULT_NONPOW2)
1101         width = image_info.Width;
1102     if (width == D3DX_DEFAULT)
1103         width = make_pow2(image_info.Width);
1104
1105     if (height == 0 || height == D3DX_DEFAULT_NONPOW2)
1106         height = image_info.Height;
1107     if (height == D3DX_DEFAULT)
1108         height = make_pow2(image_info.Height);
1109
1110     if (depth == 0 || depth == D3DX_DEFAULT_NONPOW2)
1111         depth = image_info.Depth;
1112     if (depth == D3DX_DEFAULT)
1113         depth = make_pow2(image_info.Depth);
1114
1115     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
1116         format = image_info.Format;
1117
1118     if (width == D3DX_FROM_FILE)
1119     {
1120         file_width = TRUE;
1121         width = image_info.Width;
1122     }
1123
1124     if (height == D3DX_FROM_FILE)
1125     {
1126         file_height = TRUE;
1127         height = image_info.Height;
1128     }
1129
1130     if (depth == D3DX_FROM_FILE)
1131     {
1132         file_depth = TRUE;
1133         depth = image_info.Depth;
1134     }
1135
1136     if (format == D3DFMT_FROM_FILE)
1137     {
1138         file_format = TRUE;
1139         format = image_info.Format;
1140     }
1141
1142     if (mip_levels == D3DX_FROM_FILE)
1143     {
1144         file_mip_levels = TRUE;
1145         mip_levels = image_info.MipLevels;
1146     }
1147
1148     hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, &mip_levels, usage, &format, pool);
1149     if (FAILED(hr)) return hr;
1150
1151     if ((file_width && width != image_info.Width)
1152             || (file_height && height != image_info.Height)
1153             || (file_depth && depth != image_info.Depth)
1154             || (file_format && format != image_info.Format)
1155             || (file_mip_levels && mip_levels != image_info.MipLevels))
1156         return D3DERR_NOTAVAILABLE;
1157
1158     hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
1159     if (FAILED(hr))
1160         return D3DERR_INVALIDCALL;
1161
1162     if (mip_levels > image_info.MipLevels)
1163     {
1164         FIXME("Generation of mipmaps for volume textures is not implemented yet\n");
1165         mip_levels = image_info.MipLevels;
1166     }
1167
1168     dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
1169     if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
1170     {
1171         hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
1172         tex = buftex;
1173     }
1174     else
1175     {
1176         hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, pool, &tex);
1177         buftex = NULL;
1178     }
1179
1180     if (FAILED(hr)) return hr;
1181
1182     hr = load_volume_texture_from_dds(tex, data, palette, filter, color_key, &image_info);
1183     if (FAILED(hr))
1184     {
1185         IDirect3DVolumeTexture9_Release(tex);
1186         return hr;
1187     }
1188
1189     if (buftex)
1190     {
1191         hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, pool, &tex);
1192         if (FAILED(hr))
1193         {
1194             IDirect3DVolumeTexture9_Release(buftex);
1195             return hr;
1196         }
1197
1198         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)buftex, (IDirect3DBaseTexture9 *)tex);
1199         IDirect3DVolumeTexture9_Release(buftex);
1200     }
1201
1202     if (info)
1203         *info = image_info;
1204
1205     *volume_texture = tex;
1206     return D3D_OK;
1207 }
1208
1209 static inline void fill_texture(const struct pixel_format_desc *format, BYTE *pos, const D3DXVECTOR4 *value)
1210 {
1211     DWORD c;
1212
1213     for (c = 0; c < format->bytes_per_pixel; c++)
1214         pos[c] = 0;
1215
1216     for (c = 0; c < 4; c++)
1217     {
1218         float comp_value;
1219         DWORD i, v = 0, mask32 = format->bits[c] == 32 ? ~0U : ((1 << format->bits[c]) - 1);
1220
1221         switch (c)
1222         {
1223             case 0: /* Alpha */
1224                 comp_value = value->w;
1225                 break;
1226             case 1: /* Red */
1227                 comp_value = value->x;
1228                 break;
1229             case 2: /* Green */
1230                 comp_value = value->y;
1231                 break;
1232             case 3: /* Blue */
1233                 comp_value = value->z;
1234                 break;
1235         }
1236
1237         if (format->type == FORMAT_ARGBF16)
1238             v = float_32_to_16(comp_value);
1239         else if (format->type == FORMAT_ARGBF)
1240             v = *(DWORD *)&comp_value;
1241         else if (format->type == FORMAT_ARGB)
1242             v = comp_value * ((1 << format->bits[c]) - 1) + 0.5f;
1243         else
1244             FIXME("Unhandled format type %#x\n", format->type);
1245
1246         for (i = 0; i < format->bits[c] + format->shift[c]; i += 8)
1247         {
1248             BYTE byte, mask;
1249
1250             if (format->shift[c] > i)
1251             {
1252                 mask = mask32 << (format->shift[c] - i);
1253                 byte = (v << (format->shift[c] - i)) & mask;
1254             }
1255             else
1256             {
1257                 mask = mask32 >> (i - format->shift[c]);
1258                 byte = (v >> (i - format->shift[c])) & mask;
1259             }
1260             pos[i / 8] |= byte;
1261         }
1262     }
1263 }
1264
1265 HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D function, void *funcdata)
1266 {
1267     DWORD miplevels;
1268     DWORD m, x, y;
1269     D3DSURFACE_DESC desc;
1270     D3DLOCKED_RECT lock_rect;
1271     D3DXVECTOR4 value;
1272     D3DXVECTOR2 coord, size;
1273     const struct pixel_format_desc *format;
1274     BYTE *data;
1275
1276     if (texture == NULL || function == NULL)
1277         return D3DERR_INVALIDCALL;
1278
1279     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1280
1281     for (m = 0; m < miplevels; m++)
1282     {
1283         if (FAILED(IDirect3DTexture9_GetLevelDesc(texture, m, &desc)))
1284             return D3DERR_INVALIDCALL;
1285
1286         format = get_format_info(desc.Format);
1287         if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
1288         {
1289             FIXME("Unsupported texture format %#x\n", desc.Format);
1290             return D3DERR_INVALIDCALL;
1291         }
1292
1293         if (FAILED(IDirect3DTexture9_LockRect(texture, m, &lock_rect, NULL, D3DLOCK_DISCARD)))
1294             return D3DERR_INVALIDCALL;
1295
1296         size.x = 1.0f / desc.Width;
1297         size.y = 1.0f / desc.Height;
1298
1299         data = lock_rect.pBits;
1300
1301         for (y = 0; y < desc.Height; y++)
1302         {
1303             /* The callback function expects the coordinates of the center
1304                of the texel */
1305             coord.y = (y + 0.5f) / desc.Height;
1306
1307             for (x = 0; x < desc.Width; x++)
1308             {
1309                 coord.x = (x + 0.5f) / desc.Width;
1310
1311                 function(&value, &coord, &size, funcdata);
1312
1313                 fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value);
1314             }
1315         }
1316         IDirect3DTexture9_UnlockRect(texture, m);
1317     }
1318
1319     return D3D_OK;
1320 }
1321
1322 HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device,
1323                                                        const void *src_data,
1324                                                        UINT src_data_size,
1325                                                        UINT size,
1326                                                        UINT mip_levels,
1327                                                        DWORD usage,
1328                                                        D3DFORMAT format,
1329                                                        D3DPOOL pool,
1330                                                        DWORD filter,
1331                                                        DWORD mip_filter,
1332                                                        D3DCOLOR color_key,
1333                                                        D3DXIMAGE_INFO *src_info,
1334                                                        PALETTEENTRY *palette,
1335                                                        IDirect3DCubeTexture9 **cube_texture)
1336 {
1337     HRESULT hr;
1338     D3DCAPS9 caps;
1339     UINT loaded_miplevels;
1340     D3DXIMAGE_INFO img_info;
1341     BOOL dynamic_texture;
1342     BOOL file_size = FALSE;
1343     BOOL file_format = FALSE;
1344     BOOL file_mip_levels = FALSE;
1345     IDirect3DCubeTexture9 *tex, *buftex;
1346
1347     TRACE("(%p, %p, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p)\n", device,
1348         src_data, src_data_size, size, mip_levels, usage, format, pool, filter, mip_filter,
1349         color_key, src_info, palette, cube_texture);
1350
1351     if (!device || !cube_texture || !src_data || !src_data_size)
1352         return D3DERR_INVALIDCALL;
1353
1354     hr = D3DXGetImageInfoFromFileInMemory(src_data, src_data_size, &img_info);
1355     if (FAILED(hr))
1356         return hr;
1357
1358     if (img_info.ImageFileFormat != D3DXIFF_DDS)
1359         return D3DXERR_INVALIDDATA;
1360
1361     if (img_info.Width != img_info.Height)
1362         return D3DXERR_INVALIDDATA;
1363
1364     if (size == 0 || size == D3DX_DEFAULT_NONPOW2)
1365         size = img_info.Width;
1366     if (size == D3DX_DEFAULT)
1367         size = make_pow2(img_info.Width);
1368
1369     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
1370         format = img_info.Format;
1371
1372     if (size == D3DX_FROM_FILE)
1373     {
1374         file_size = TRUE;
1375         size = img_info.Width;
1376     }
1377
1378     if (format == D3DFMT_FROM_FILE)
1379     {
1380         file_format = TRUE;
1381         format = img_info.Format;
1382     }
1383
1384     if (mip_levels == D3DX_FROM_FILE)
1385     {
1386         file_mip_levels = TRUE;
1387         mip_levels = img_info.MipLevels;
1388     }
1389
1390     hr = D3DXCheckCubeTextureRequirements(device, &size, &mip_levels, usage, &format, pool);
1391     if (FAILED(hr))
1392         return hr;
1393
1394     if ((file_size && size != img_info.Width)
1395             || (file_format && format != img_info.Format)
1396             || (file_mip_levels && mip_levels != img_info.MipLevels))
1397         return D3DERR_NOTAVAILABLE;
1398
1399     hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
1400     if (FAILED(hr))
1401         return D3DERR_INVALIDCALL;
1402
1403     if (mip_levels > img_info.MipLevels && (D3DFMT_DXT1 <= img_info.Format && img_info.Format <= D3DFMT_DXT5))
1404     {
1405         FIXME("Generation of mipmaps for compressed pixel formats not supported yet\n");
1406         mip_levels = img_info.MipLevels;
1407     }
1408
1409     dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
1410     if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
1411     {
1412         hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
1413         tex = buftex;
1414     }
1415     else
1416     {
1417         hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, pool, &tex);
1418         buftex = NULL;
1419     }
1420     if (FAILED(hr))
1421         return hr;
1422
1423     hr = load_cube_texture_from_dds(tex, src_data, palette, filter, color_key, &img_info);
1424     if (FAILED(hr))
1425     {
1426         IDirect3DCubeTexture9_Release(tex);
1427         return hr;
1428     }
1429
1430     loaded_miplevels = min(IDirect3DCubeTexture9_GetLevelCount(tex), img_info.MipLevels);
1431     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, palette, loaded_miplevels - 1, mip_filter);
1432     if (FAILED(hr))
1433     {
1434         IDirect3DCubeTexture9_Release(tex);
1435         return hr;
1436     }
1437
1438     if (buftex)
1439     {
1440         hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, pool, &tex);
1441         if (FAILED(hr))
1442         {
1443             IDirect3DCubeTexture9_Release(buftex);
1444             return hr;
1445         }
1446
1447         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)buftex, (IDirect3DBaseTexture9 *)tex);
1448         IDirect3DCubeTexture9_Release(buftex);
1449     }
1450
1451     if (src_info)
1452         *src_info = img_info;
1453
1454     *cube_texture = tex;
1455     return D3D_OK;
1456 }
1457
1458
1459 HRESULT WINAPI D3DXCreateCubeTextureFromFileA(IDirect3DDevice9 *device,
1460                                               const char *src_filename,
1461                                               IDirect3DCubeTexture9 **cube_texture)
1462 {
1463     int len;
1464     HRESULT hr;
1465     WCHAR *filename;
1466     void *data;
1467     DWORD data_size;
1468
1469     TRACE("(%p, %s, %p): relay\n", device, wine_dbgstr_a(src_filename), cube_texture);
1470
1471     if (!src_filename) return D3DERR_INVALIDCALL;
1472
1473     len = MultiByteToWideChar(CP_ACP, 0, src_filename, -1, NULL, 0);
1474     filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1475     if (!filename) return E_OUTOFMEMORY;
1476     MultiByteToWideChar(CP_ACP, 0, src_filename, -1, filename, len);
1477
1478     hr = map_view_of_file(filename, &data, &data_size);
1479     if (FAILED(hr))
1480     {
1481         HeapFree(GetProcessHeap(), 0, filename);
1482         return D3DXERR_INVALIDDATA;
1483     }
1484
1485     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT,
1486         0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, cube_texture);
1487
1488     UnmapViewOfFile(data);
1489     HeapFree(GetProcessHeap(), 0, filename);
1490     return hr;
1491 }
1492
1493 HRESULT WINAPI D3DXCreateCubeTextureFromFileW(IDirect3DDevice9 *device,
1494                                               const WCHAR *src_filename,
1495                                               IDirect3DCubeTexture9 **cube_texture)
1496 {
1497     HRESULT hr;
1498     void *data;
1499     DWORD data_size;
1500
1501     TRACE("(%p, %s, %p): relay\n", device, wine_dbgstr_w(src_filename), cube_texture);
1502
1503     hr = map_view_of_file(src_filename, &data, &data_size);
1504     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
1505
1506     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT,
1507         0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, cube_texture);
1508
1509     UnmapViewOfFile(data);
1510     return hr;
1511 }
1512
1513 HRESULT WINAPI D3DXCreateCubeTextureFromFileExA(IDirect3DDevice9 *device,
1514                                                 const char *src_filename,
1515                                                 UINT size,
1516                                                 UINT mip_levels,
1517                                                 DWORD usage,
1518                                                 D3DFORMAT format,
1519                                                 D3DPOOL pool,
1520                                                 DWORD filter,
1521                                                 DWORD mip_filter,
1522                                                 D3DCOLOR color_key,
1523                                                 D3DXIMAGE_INFO *image_info,
1524                                                 PALETTEENTRY *palette,
1525                                                 IDirect3DCubeTexture9 **cube_texture)
1526 {
1527     int len;
1528     HRESULT hr;
1529     WCHAR *filename;
1530     void *data;
1531     DWORD data_size;
1532
1533     TRACE("(%p, %s, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n",
1534             device, wine_dbgstr_a(src_filename), size, mip_levels, usage, format,
1535             pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1536
1537     if (!src_filename) return D3DERR_INVALIDCALL;
1538
1539     len = MultiByteToWideChar(CP_ACP, 0, src_filename, -1, NULL, 0);
1540     filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1541     if (!filename) return E_OUTOFMEMORY;
1542     MultiByteToWideChar(CP_ACP, 0, src_filename, -1, filename, len);
1543
1544     hr = map_view_of_file(filename, &data, &data_size);
1545     if (FAILED(hr))
1546     {
1547         HeapFree(GetProcessHeap(), 0, filename);
1548         return D3DXERR_INVALIDDATA;
1549     }
1550
1551     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, size, mip_levels,
1552         usage, format, pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1553
1554     UnmapViewOfFile(data);
1555     HeapFree(GetProcessHeap(), 0, filename);
1556     return hr;
1557 }
1558
1559 HRESULT WINAPI D3DXCreateCubeTextureFromFileExW(IDirect3DDevice9 *device,
1560                                                 const WCHAR *src_filename,
1561                                                 UINT size,
1562                                                 UINT mip_levels,
1563                                                 DWORD usage,
1564                                                 D3DFORMAT format,
1565                                                 D3DPOOL pool,
1566                                                 DWORD filter,
1567                                                 DWORD mip_filter,
1568                                                 D3DCOLOR color_key,
1569                                                 D3DXIMAGE_INFO *image_info,
1570                                                 PALETTEENTRY *palette,
1571                                                 IDirect3DCubeTexture9 **cube_texture)
1572 {
1573     HRESULT hr;
1574     void *data;
1575     DWORD data_size;
1576
1577     TRACE("(%p, %s, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n",
1578             device, wine_dbgstr_w(src_filename), size, mip_levels, usage, format,
1579             pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1580
1581     hr = map_view_of_file(src_filename, &data, &data_size);
1582     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
1583
1584     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, size, mip_levels,
1585         usage, format, pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1586
1587     UnmapViewOfFile(data);
1588     return hr;
1589 }
1590
1591 enum cube_coord
1592 {
1593     XCOORD = 0,
1594     XCOORDINV = 1,
1595     YCOORD = 2,
1596     YCOORDINV = 3,
1597     ZERO = 4,
1598     ONE = 5
1599 };
1600
1601 static float get_cube_coord(enum cube_coord coord, unsigned int x, unsigned int y, unsigned int size)
1602 {
1603     switch (coord)
1604     {
1605         case XCOORD:
1606             return x + 0.5f;
1607         case XCOORDINV:
1608             return size - x - 0.5f;
1609         case YCOORD:
1610             return y + 0.5f;
1611         case YCOORDINV:
1612             return size - y - 0.5f;
1613         case ZERO:
1614             return 0.0f;
1615         case ONE:
1616             return size;
1617        default:
1618            ERR("Unexpected coordinate value\n");
1619            return 0.0f;
1620     }
1621 }
1622
1623 HRESULT WINAPI D3DXFillCubeTexture(struct IDirect3DCubeTexture9 *texture, LPD3DXFILL3D function, void *funcdata)
1624 {
1625     DWORD miplevels;
1626     DWORD m, x, y, f;
1627     D3DSURFACE_DESC desc;
1628     D3DLOCKED_RECT lock_rect;
1629     D3DXVECTOR4 value;
1630     D3DXVECTOR3 coord, size;
1631     const struct pixel_format_desc *format;
1632     BYTE *data;
1633     static const enum cube_coord coordmap[6][3] =
1634         {
1635             {ONE, YCOORDINV, XCOORDINV},
1636             {ZERO, YCOORDINV, XCOORD},
1637             {XCOORD, ONE, YCOORD},
1638             {XCOORD, ZERO, YCOORDINV},
1639             {XCOORD, YCOORDINV, ONE},
1640             {XCOORDINV, YCOORDINV, ZERO}
1641         };
1642
1643     if (texture == NULL || function == NULL)
1644         return D3DERR_INVALIDCALL;
1645
1646     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1647
1648     for (m = 0; m < miplevels; m++)
1649     {
1650         if (FAILED(IDirect3DCubeTexture9_GetLevelDesc(texture, m, &desc)))
1651             return D3DERR_INVALIDCALL;
1652
1653         format = get_format_info(desc.Format);
1654         if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
1655         {
1656             FIXME("Unsupported texture format %#x\n", desc.Format);
1657             return D3DERR_INVALIDCALL;
1658         }
1659
1660         for (f = 0; f < 6; f++)
1661         {
1662             if (FAILED(IDirect3DCubeTexture9_LockRect(texture, f, m, &lock_rect, NULL, D3DLOCK_DISCARD)))
1663                 return D3DERR_INVALIDCALL;
1664
1665             size.x = (f == 0) || (f == 1) ? 0.0f : 2.0f / desc.Width;
1666             size.y = (f == 2) || (f == 3) ? 0.0f : 2.0f / desc.Width;
1667             size.z = (f == 4) || (f == 5) ? 0.0f : 2.0f / desc.Width;
1668
1669             data = lock_rect.pBits;
1670
1671             for (y = 0; y < desc.Height; y++)
1672             {
1673                 for (x = 0; x < desc.Width; x++)
1674                 {
1675                     coord.x = get_cube_coord(coordmap[f][0], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1676                     coord.y = get_cube_coord(coordmap[f][1], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1677                     coord.z = get_cube_coord(coordmap[f][2], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1678
1679                     function(&value, &coord, &size, funcdata);
1680
1681                     fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value);
1682                 }
1683             }
1684             IDirect3DCubeTexture9_UnlockRect(texture, f, m);
1685         }
1686     }
1687
1688     return D3D_OK;
1689 }
1690
1691 HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LPD3DXFILL3D function, void *funcdata)
1692 {
1693     DWORD miplevels;
1694     DWORD m, x, y, z;
1695     D3DVOLUME_DESC desc;
1696     D3DLOCKED_BOX lock_box;
1697     D3DXVECTOR4 value;
1698     D3DXVECTOR3 coord, size;
1699     const struct pixel_format_desc *format;
1700     BYTE *data;
1701
1702     if (texture == NULL || function == NULL)
1703         return D3DERR_INVALIDCALL;
1704
1705     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1706
1707     for (m = 0; m < miplevels; m++)
1708     {
1709         if (FAILED(IDirect3DVolumeTexture9_GetLevelDesc(texture, m, &desc)))
1710             return D3DERR_INVALIDCALL;
1711
1712         format = get_format_info(desc.Format);
1713         if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
1714         {
1715             FIXME("Unsupported texture format %#x\n", desc.Format);
1716             return D3DERR_INVALIDCALL;
1717         }
1718
1719         if (FAILED(IDirect3DVolumeTexture9_LockBox(texture, m, &lock_box, NULL, D3DLOCK_DISCARD)))
1720             return D3DERR_INVALIDCALL;
1721
1722         size.x = 1.0f / desc.Width;
1723         size.y = 1.0f / desc.Height;
1724         size.z = 1.0f / desc.Depth;
1725
1726         data = lock_box.pBits;
1727
1728         for (z = 0; z < desc.Depth; z++)
1729         {
1730             /* The callback function expects the coordinates of the center
1731                of the texel */
1732             coord.z = (z + 0.5f) / desc.Depth;
1733
1734             for (y = 0; y < desc.Height; y++)
1735             {
1736                 coord.y = (y + 0.5f) / desc.Height;
1737
1738                 for (x = 0; x < desc.Width; x++)
1739                 {
1740                     coord.x = (x + 0.5f) / desc.Width;
1741
1742                     function(&value, &coord, &size, funcdata);
1743
1744                     fill_texture(format, data + z * lock_box.SlicePitch + y * lock_box.RowPitch
1745                             + x * format->bytes_per_pixel, &value);
1746                 }
1747             }
1748         }
1749         IDirect3DVolumeTexture9_UnlockBox(texture, m);
1750     }
1751
1752     return D3D_OK;
1753 }
1754
1755 HRESULT WINAPI D3DXSaveTextureToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1756         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
1757 {
1758     int len;
1759     WCHAR *filename;
1760     HRESULT hr;
1761     ID3DXBuffer *buffer;
1762
1763     TRACE("(%s, %#x, %p, %p): relay\n",
1764             wine_dbgstr_a(dst_filename), file_format, src_texture, src_palette);
1765
1766     if (!dst_filename) return D3DERR_INVALIDCALL;
1767
1768     len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0);
1769     filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1770     if (!filename) return E_OUTOFMEMORY;
1771     MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len);
1772
1773     hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, src_texture, src_palette);
1774     if (SUCCEEDED(hr))
1775     {
1776         hr = write_buffer_to_file(filename, buffer);
1777         ID3DXBuffer_Release(buffer);
1778     }
1779
1780     HeapFree(GetProcessHeap(), 0, filename);
1781     return hr;
1782 }
1783
1784 HRESULT WINAPI D3DXSaveTextureToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1785         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
1786 {
1787     HRESULT hr;
1788     ID3DXBuffer *buffer;
1789
1790     TRACE("(%s, %#x, %p, %p): relay\n",
1791         wine_dbgstr_w(dst_filename), file_format, src_texture, src_palette);
1792
1793     if (!dst_filename) return D3DERR_INVALIDCALL;
1794
1795     hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, src_texture, src_palette);
1796     if (SUCCEEDED(hr))
1797     {
1798         hr = write_buffer_to_file(dst_filename, buffer);
1799         ID3DXBuffer_Release(buffer);
1800     }
1801
1802     return hr;
1803 }
1804
1805 HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format,
1806         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
1807 {
1808     HRESULT hr;
1809     D3DRESOURCETYPE type;
1810     IDirect3DSurface9 *surface;
1811
1812     TRACE("(%p, %#x, %p, %p)\n",
1813         dst_buffer, file_format, src_texture, src_palette);
1814
1815     if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL;
1816
1817     if (file_format == D3DXIFF_DDS)
1818     {
1819         FIXME("DDS file format isn't supported yet\n");
1820         return E_NOTIMPL;
1821     }
1822
1823     type = IDirect3DBaseTexture9_GetType(src_texture);
1824     switch (type)
1825     {
1826         case D3DRTYPE_TEXTURE:
1827         case D3DRTYPE_CUBETEXTURE:
1828             hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface);
1829             break;
1830         case D3DRTYPE_VOLUMETEXTURE:
1831             FIXME("Volume textures aren't supported yet\n");
1832             return E_NOTIMPL;
1833         default:
1834             return D3DERR_INVALIDCALL;
1835     }
1836
1837     if (SUCCEEDED(hr))
1838     {
1839         hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL);
1840         IDirect3DSurface9_Release(surface);
1841     }
1842
1843     return hr;
1844 }