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