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