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