xref: /reactos/dll/directx/wine/d3dx9_36/texture.c (revision 02e84521)
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 "config.h"
23 #include "wine/port.h"
24 
25 #include "d3dx9_private.h"
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
28 
29 /* Returns TRUE if num is a power of 2, FALSE if not, or if 0 */
30 static BOOL is_pow2(UINT num)
31 {
32     return !(num & (num - 1));
33 }
34 
35 /* Returns the smallest power of 2 which is greater than or equal to num */
36 static UINT make_pow2(UINT num)
37 {
38     UINT result = 1;
39 
40     /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */
41     if (num >= 0x80000000)
42         return 0x80000000;
43 
44     while (result < num)
45         result <<= 1;
46 
47     return result;
48 }
49 
50 static HRESULT get_surface(D3DRESOURCETYPE type, struct IDirect3DBaseTexture9 *tex,
51         int face, UINT level, struct IDirect3DSurface9 **surf)
52 {
53     switch (type)
54     {
55         case D3DRTYPE_TEXTURE:
56             return IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) tex, level, surf);
57         case D3DRTYPE_CUBETEXTURE:
58             return IDirect3DCubeTexture9_GetCubeMapSurface((IDirect3DCubeTexture9*) tex, face, level, surf);
59         default:
60             ERR("Unexpected texture type\n");
61             return E_NOTIMPL;
62     }
63 }
64 
65 HRESULT WINAPI D3DXFilterTexture(IDirect3DBaseTexture9 *texture,
66                                  const PALETTEENTRY *palette,
67                                  UINT srclevel,
68                                  DWORD filter)
69 {
70     UINT level;
71     HRESULT hr;
72     D3DRESOURCETYPE type;
73 
74     TRACE("(%p, %p, %u, %#x)\n", texture, palette, srclevel, filter);
75 
76     if (!texture)
77         return D3DERR_INVALIDCALL;
78 
79     if ((filter & 0xFFFF) > D3DX_FILTER_BOX && filter != D3DX_DEFAULT)
80         return D3DERR_INVALIDCALL;
81 
82     if (srclevel == D3DX_DEFAULT)
83         srclevel = 0;
84     else if (srclevel >= IDirect3DBaseTexture9_GetLevelCount(texture))
85         return D3DERR_INVALIDCALL;
86 
87     switch (type = IDirect3DBaseTexture9_GetType(texture))
88     {
89         case D3DRTYPE_TEXTURE:
90         case D3DRTYPE_CUBETEXTURE:
91         {
92             IDirect3DSurface9 *topsurf, *mipsurf;
93             D3DSURFACE_DESC desc;
94             int i, numfaces;
95 
96             if (type == D3DRTYPE_TEXTURE)
97             {
98                 numfaces = 1;
99                 IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
100             }
101             else
102             {
103                 numfaces = 6;
104                 IDirect3DCubeTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
105             }
106 
107             if (filter == D3DX_DEFAULT)
108             {
109                 if (is_pow2(desc.Width) && is_pow2(desc.Height))
110                     filter = D3DX_FILTER_BOX;
111                 else
112                     filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER;
113             }
114 
115             for (i = 0; i < numfaces; i++)
116             {
117                 level = srclevel + 1;
118                 hr = get_surface(type, texture, i, srclevel, &topsurf);
119 
120                 if (FAILED(hr))
121                     return D3DERR_INVALIDCALL;
122 
123                 while (get_surface(type, texture, i, level, &mipsurf) == D3D_OK)
124                 {
125                     hr = D3DXLoadSurfaceFromSurface(mipsurf, palette, NULL, topsurf, palette, NULL, filter, 0);
126                     IDirect3DSurface9_Release(topsurf);
127                     topsurf = mipsurf;
128 
129                     if (FAILED(hr))
130                         break;
131 
132                     level++;
133                 }
134 
135                 IDirect3DSurface9_Release(topsurf);
136                 if (FAILED(hr))
137                     return hr;
138             }
139 
140             return D3D_OK;
141         }
142 
143         case D3DRTYPE_VOLUMETEXTURE:
144         {
145             D3DVOLUME_DESC desc;
146             int level, level_count;
147             IDirect3DVolume9 *top_volume, *mip_volume;
148             IDirect3DVolumeTexture9 *volume_texture = (IDirect3DVolumeTexture9*) texture;
149 
150             IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, srclevel, &desc);
151 
152             if (filter == D3DX_DEFAULT)
153             {
154                 if (is_pow2(desc.Width) && is_pow2(desc.Height) && is_pow2(desc.Depth))
155                     filter = D3DX_FILTER_BOX;
156                 else
157                     filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER;
158             }
159 
160             hr = IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, srclevel, &top_volume);
161             if (FAILED(hr))
162                 return hr;
163 
164             level_count = IDirect3DVolumeTexture9_GetLevelCount(volume_texture);
165             for (level = srclevel + 1; level < level_count; level++)
166             {
167                 IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, level, &mip_volume);
168                 hr = D3DXLoadVolumeFromVolume(mip_volume, palette, NULL, top_volume, palette, NULL, filter, 0);
169                 IDirect3DVolume9_Release(top_volume);
170                 top_volume = mip_volume;
171 
172                 if (FAILED(hr))
173                     break;
174             }
175 
176             IDirect3DVolume9_Release(top_volume);
177             if (FAILED(hr))
178                 return hr;
179 
180             return D3D_OK;
181         }
182 
183         default:
184             return D3DERR_INVALIDCALL;
185     }
186 }
187 
188 static D3DFORMAT get_luminance_replacement_format(D3DFORMAT format)
189 {
190     static const struct
191     {
192         D3DFORMAT luminance_format;
193         D3DFORMAT replacement_format;
194     } luminance_replacements[] =
195     {
196         {D3DFMT_L8, D3DFMT_X8R8G8B8},
197         {D3DFMT_A8L8, D3DFMT_A8R8G8B8},
198         {D3DFMT_A4L4, D3DFMT_A4R4G4B4},
199         {D3DFMT_L16, D3DFMT_A16B16G16R16}
200     };
201     unsigned int i;
202 
203     for (i = 0; i < ARRAY_SIZE(luminance_replacements); ++i)
204         if (format == luminance_replacements[i].luminance_format)
205             return luminance_replacements[i].replacement_format;
206     return format;
207 }
208 
209 HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height,
210         UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
211 {
212     UINT w = (width && *width) ? *width : 1;
213     UINT h = (height && *height) ? *height : 1;
214     D3DCAPS9 caps;
215     D3DDEVICE_CREATION_PARAMETERS params;
216     IDirect3D9 *d3d = NULL;
217     D3DDISPLAYMODE mode;
218     HRESULT hr;
219     D3DFORMAT usedformat = D3DFMT_UNKNOWN;
220     const struct pixel_format_desc *fmt;
221 
222     TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool);
223 
224     if (!device)
225         return D3DERR_INVALIDCALL;
226 
227     /* usage */
228     if (usage == D3DX_DEFAULT)
229         usage = 0;
230     if (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES))
231         return D3DERR_INVALIDCALL;
232 
233     /* pool */
234     if ((pool != D3DPOOL_DEFAULT) && (pool != D3DPOOL_MANAGED) && (pool != D3DPOOL_SYSTEMMEM) && (pool != D3DPOOL_SCRATCH))
235         return D3DERR_INVALIDCALL;
236 
237     /* format */
238     if (format)
239     {
240         TRACE("Requested format %x\n", *format);
241         usedformat = *format;
242     }
243 
244     hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
245 
246     if (FAILED(hr))
247         goto cleanup;
248 
249     hr = IDirect3DDevice9_GetCreationParameters(device, &params);
250 
251     if (FAILED(hr))
252         goto cleanup;
253 
254     hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
255 
256     if (FAILED(hr))
257         goto cleanup;
258 
259     if ((usedformat == D3DFMT_UNKNOWN) || (usedformat == D3DX_DEFAULT))
260         usedformat = D3DFMT_A8R8G8B8;
261 
262     fmt = get_format_info(usedformat);
263 
264     hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format,
265         usage, D3DRTYPE_TEXTURE, usedformat);
266     if (FAILED(hr))
267     {
268         BOOL allow_24bits;
269         int bestscore = INT_MIN, i = 0, j;
270         unsigned int channels;
271         const struct pixel_format_desc *curfmt, *bestfmt = NULL;
272 
273         TRACE("Requested format is not supported, looking for a fallback.\n");
274 
275         if (!fmt)
276         {
277             FIXME("Pixel format %x not handled\n", usedformat);
278             goto cleanup;
279         }
280         fmt = get_format_info(get_luminance_replacement_format(usedformat));
281 
282         allow_24bits = fmt->bytes_per_pixel == 3;
283         channels = !!fmt->bits[0] + !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3];
284         usedformat = D3DFMT_UNKNOWN;
285 
286         while ((curfmt = get_format_info_idx(i)))
287         {
288             unsigned int curchannels = !!curfmt->bits[0] + !!curfmt->bits[1]
289                     + !!curfmt->bits[2] + !!curfmt->bits[3];
290             int score;
291 
292             i++;
293 
294             if (curchannels < channels)
295                 continue;
296             if (curfmt->bytes_per_pixel == 3 && !allow_24bits)
297                 continue;
298 
299             hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
300                 mode.Format, usage, D3DRTYPE_TEXTURE, curfmt->format);
301             if (FAILED(hr))
302                 continue;
303 
304             /* This format can be used, let's evaluate it.
305                Weights chosen quite arbitrarily... */
306             score = 512 * (curfmt->type == fmt->type);
307             score -= 32 * (curchannels - channels);
308 
309             for (j = 0; j < 4; j++)
310             {
311                 int diff = curfmt->bits[j] - fmt->bits[j];
312                 score -= (diff < 0 ? -diff * 8 : diff) * (j == 0 ? 1 : 2);
313             }
314 
315             if (score > bestscore)
316             {
317                 bestscore = score;
318                 usedformat = curfmt->format;
319                 bestfmt = curfmt;
320             }
321         }
322         fmt = bestfmt;
323         hr = D3D_OK;
324     }
325 
326     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
327         return D3DERR_INVALIDCALL;
328 
329     if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT))
330         w = h = 256;
331     else if (w == D3DX_DEFAULT)
332         w = (height ? h : 256);
333     else if (h == D3DX_DEFAULT)
334         h = (width ? w : 256);
335 
336     if (fmt->block_width != 1 || fmt->block_height != 1)
337     {
338         if (w % fmt->block_width)
339             w += fmt->block_width - w % fmt->block_width;
340         if (h % fmt->block_height)
341             h += fmt->block_height - h % fmt->block_height;
342     }
343 
344     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w)))
345         w = make_pow2(w);
346 
347     if (w > caps.MaxTextureWidth)
348         w = caps.MaxTextureWidth;
349 
350     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h)))
351         h = make_pow2(h);
352 
353     if (h > caps.MaxTextureHeight)
354         h = caps.MaxTextureHeight;
355 
356     if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
357     {
358         if (w > h)
359             h = w;
360         else
361             w = h;
362     }
363 
364     if (width)
365         *width = w;
366 
367     if (height)
368         *height = h;
369 
370     if (miplevels && (usage & D3DUSAGE_AUTOGENMIPMAP))
371     {
372         if (*miplevels > 1)
373             *miplevels = 0;
374     }
375     else if (miplevels)
376     {
377         UINT max_mipmaps = 1;
378 
379         if (!width && !height)
380             max_mipmaps = 9;    /* number of mipmaps in a 256x256 texture */
381         else
382         {
383             UINT max_dimen = max(w, h);
384 
385             while (max_dimen > 1)
386             {
387                 max_dimen >>= 1;
388                 max_mipmaps++;
389             }
390         }
391 
392         if (*miplevels == 0 || *miplevels > max_mipmaps)
393             *miplevels = max_mipmaps;
394     }
395 
396 cleanup:
397 
398     if (d3d)
399         IDirect3D9_Release(d3d);
400 
401     if (FAILED(hr))
402         return hr;
403 
404     if (usedformat == D3DFMT_UNKNOWN)
405     {
406         WARN("Couldn't find a suitable pixel format\n");
407         return D3DERR_NOTAVAILABLE;
408     }
409 
410     TRACE("Format chosen: %x\n", usedformat);
411     if (format)
412         *format = usedformat;
413 
414     return D3D_OK;
415 }
416 
417 HRESULT WINAPI D3DXCheckCubeTextureRequirements(struct IDirect3DDevice9 *device, UINT *size,
418         UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
419 {
420     D3DCAPS9 caps;
421     UINT s = (size && *size) ? *size : 256;
422     HRESULT hr;
423 
424     TRACE("(%p, %p, %p, %u, %p, %u)\n", device, size, miplevels, usage, format, pool);
425 
426     if (s == D3DX_DEFAULT)
427         s = 256;
428 
429     if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
430         return D3DERR_INVALIDCALL;
431 
432     if (!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
433         return D3DERR_NOTAVAILABLE;
434 
435     /* ensure width/height is power of 2 */
436     if ((caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && (!is_pow2(s)))
437         s = make_pow2(s);
438 
439     hr = D3DXCheckTextureRequirements(device, &s, &s, miplevels, usage, format, pool);
440 
441     if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP))
442     {
443         if(miplevels)
444             *miplevels = 1;
445     }
446 
447     if (size)
448         *size = s;
449 
450     return hr;
451 }
452 
453 HRESULT WINAPI D3DXCheckVolumeTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height,
454         UINT *depth, UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
455 {
456     D3DCAPS9 caps;
457     UINT w = width ? *width : D3DX_DEFAULT;
458     UINT h = height ? *height : D3DX_DEFAULT;
459     UINT d = (depth && *depth) ? *depth : 1;
460     HRESULT hr;
461 
462     TRACE("(%p, %p, %p, %p, %p, %u, %p, %u)\n", device, width, height, depth, miplevels,
463           usage, format, pool);
464 
465     if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
466         return D3DERR_INVALIDCALL;
467 
468     if (!(caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP))
469         return D3DERR_NOTAVAILABLE;
470 
471     hr = D3DXCheckTextureRequirements(device, &w, &h, NULL, usage, format, pool);
472     if (d == D3DX_DEFAULT)
473         d = 1;
474 
475     /* ensure width/height is power of 2 */
476     if ((caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) &&
477         (!is_pow2(w) || !is_pow2(h) || !is_pow2(d)))
478     {
479         w = make_pow2(w);
480         h = make_pow2(h);
481         d = make_pow2(d);
482     }
483 
484     if (w > caps.MaxVolumeExtent)
485         w = caps.MaxVolumeExtent;
486     if (h > caps.MaxVolumeExtent)
487         h = caps.MaxVolumeExtent;
488     if (d > caps.MaxVolumeExtent)
489         d = caps.MaxVolumeExtent;
490 
491     if (miplevels)
492     {
493         if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP))
494             *miplevels = 1;
495         else if ((usage & D3DUSAGE_AUTOGENMIPMAP))
496         {
497             if (*miplevels > 1)
498                 *miplevels = 0;
499         }
500         else
501         {
502             UINT max_mipmaps = 1;
503             UINT max_dimen = max(max(w, h), d);
504 
505             while (max_dimen > 1)
506             {
507                 max_dimen >>= 1;
508                 max_mipmaps++;
509             }
510 
511             if (*miplevels == 0 || *miplevels > max_mipmaps)
512                 *miplevels = max_mipmaps;
513         }
514     }
515 
516     if (width)
517         *width = w;
518     if (height)
519         *height = h;
520     if (depth)
521         *depth = d;
522 
523     return hr;
524 }
525 
526 HRESULT WINAPI D3DXCreateTexture(struct IDirect3DDevice9 *device, UINT width, UINT height,
527         UINT miplevels, DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DTexture9 **texture)
528 {
529     HRESULT hr;
530 
531     TRACE("device %p, width %u, height %u, miplevels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
532             device, width, height, miplevels, usage, format, pool, texture);
533 
534     if (!device || !texture)
535         return D3DERR_INVALIDCALL;
536 
537     if (FAILED(hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool)))
538         return hr;
539 
540     return IDirect3DDevice9_CreateTexture(device, width, height, miplevels, usage, format, pool, texture, NULL);
541 }
542 
543 static D3DFORMAT get_alpha_replacement_format(D3DFORMAT format)
544 {
545     static const struct
546     {
547         D3DFORMAT orig_format;
548         D3DFORMAT replacement_format;
549     }
550     replacement_formats[] =
551     {
552         {D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8},
553         {D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5},
554         {D3DFMT_X4R4G4B4, D3DFMT_A4R4G4B4},
555         {D3DFMT_X8B8G8R8, D3DFMT_A8B8G8R8},
556         {D3DFMT_L8, D3DFMT_A8L8},
557     };
558     unsigned int i;
559 
560     for (i = 0; i < ARRAY_SIZE(replacement_formats); ++i)
561         if (replacement_formats[i].orig_format == format)
562             return replacement_formats[i].replacement_format;
563     return format;
564 }
565 
566 HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *device, const void *srcdata,
567         UINT srcdatasize, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
568         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
569         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
570 {
571     IDirect3DTexture9 **texptr;
572     IDirect3DTexture9 *buftex;
573     IDirect3DSurface9 *surface;
574     BOOL dynamic_texture, format_specified = FALSE;
575     D3DXIMAGE_INFO imginfo;
576     UINT loaded_miplevels, skip_levels;
577     D3DCAPS9 caps;
578     HRESULT hr;
579 
580     TRACE("device %p, srcdata %p, srcdatasize %u, width %u, height %u, miplevels %u,"
581             " usage %#x, format %#x, pool %#x, filter %#x, mipfilter %#x, colorkey %#x,"
582             " srcinfo %p, palette %p, texture %p.\n",
583             device, srcdata, srcdatasize, width, height, miplevels, usage, format, pool,
584             filter, mipfilter, colorkey, srcinfo, palette, texture);
585 
586     /* check for invalid parameters */
587     if (!device || !texture || !srcdata || !srcdatasize)
588         return D3DERR_INVALIDCALL;
589 
590     hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo);
591     if (FAILED(hr))
592     {
593         FIXME("Unrecognized file format, returning failure.\n");
594         *texture = NULL;
595         return hr;
596     }
597 
598     /* handle default values */
599     if (width == 0 || width == D3DX_DEFAULT_NONPOW2)
600         width = imginfo.Width;
601 
602     if (height == 0 || height == D3DX_DEFAULT_NONPOW2)
603         height = imginfo.Height;
604 
605     if (width == D3DX_DEFAULT)
606         width = make_pow2(imginfo.Width);
607 
608     if (height == D3DX_DEFAULT)
609         height = make_pow2(imginfo.Height);
610 
611     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
612         format = imginfo.Format;
613     else
614         format_specified = TRUE;
615 
616     if (width == D3DX_FROM_FILE)
617     {
618         width = imginfo.Width;
619     }
620 
621     if (height == D3DX_FROM_FILE)
622     {
623         height = imginfo.Height;
624     }
625 
626     if (format == D3DFMT_FROM_FILE)
627     {
628         format = imginfo.Format;
629     }
630 
631     if (miplevels == D3DX_FROM_FILE)
632     {
633         miplevels = imginfo.MipLevels;
634     }
635 
636     skip_levels = mipfilter != D3DX_DEFAULT ? mipfilter >> D3DX_SKIP_DDS_MIP_LEVELS_SHIFT : 0;
637     if (skip_levels && imginfo.MipLevels > skip_levels)
638     {
639         TRACE("Skipping the first %u (of %u) levels of a DDS mipmapped texture.\n",
640                 skip_levels, imginfo.MipLevels);
641         TRACE("Texture level 0 dimensions are %ux%u.\n", imginfo.Width, imginfo.Height);
642         width >>= skip_levels;
643         height >>= skip_levels;
644         miplevels -= skip_levels;
645     }
646     else
647     {
648         skip_levels = 0;
649     }
650 
651     /* fix texture creation parameters */
652     hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
653     if (FAILED(hr))
654     {
655         FIXME("Couldn't find suitable texture parameters.\n");
656         *texture = NULL;
657         return hr;
658     }
659 
660     if (colorkey && !format_specified)
661         format = get_alpha_replacement_format(format);
662 
663     if (imginfo.MipLevels < miplevels && (D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5))
664     {
665         FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n");
666         miplevels = imginfo.MipLevels;
667     }
668     if (imginfo.ResourceType == D3DRTYPE_VOLUMETEXTURE
669             && D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5 && miplevels > 1)
670     {
671         FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n");
672         miplevels = 1;
673     }
674 
675     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
676         return D3DERR_INVALIDCALL;
677 
678     /* Create the to-be-filled texture */
679     dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
680     if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
681     {
682         hr = D3DXCreateTexture(device, width, height, miplevels, 0, format, D3DPOOL_SYSTEMMEM, &buftex);
683         texptr = &buftex;
684     }
685     else
686     {
687         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
688         texptr = texture;
689     }
690 
691     if (FAILED(hr))
692     {
693         FIXME("Texture creation failed.\n");
694         *texture = NULL;
695         return hr;
696     }
697 
698     TRACE("Texture created correctly. Now loading the texture data into it.\n");
699     if (imginfo.ImageFileFormat != D3DXIFF_DDS)
700     {
701         IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface);
702         hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL);
703         IDirect3DSurface9_Release(surface);
704         loaded_miplevels = min(IDirect3DTexture9_GetLevelCount(*texptr), imginfo.MipLevels);
705     }
706     else
707     {
708         hr = load_texture_from_dds(*texptr, srcdata, palette, filter, colorkey, &imginfo, skip_levels,
709                 &loaded_miplevels);
710     }
711 
712     if (FAILED(hr))
713     {
714         FIXME("Texture loading failed.\n");
715         IDirect3DTexture9_Release(*texptr);
716         *texture = NULL;
717         return hr;
718     }
719 
720     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, loaded_miplevels - 1, mipfilter);
721     if (FAILED(hr))
722     {
723         FIXME("Texture filtering failed.\n");
724         IDirect3DTexture9_Release(*texptr);
725         *texture = NULL;
726         return hr;
727     }
728 
729     /* Move the data to the actual texture if necessary */
730     if (texptr == &buftex)
731     {
732         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
733 
734         if (FAILED(hr))
735         {
736             IDirect3DTexture9_Release(buftex);
737             *texture = NULL;
738             return hr;
739         }
740 
741         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)buftex, (IDirect3DBaseTexture9*)(*texture));
742         IDirect3DTexture9_Release(buftex);
743     }
744 
745     if (srcinfo)
746         *srcinfo = imginfo;
747 
748     return D3D_OK;
749 }
750 
751 HRESULT WINAPI D3DXCreateTextureFromFileInMemory(struct IDirect3DDevice9 *device,
752         const void *srcdata, UINT srcdatasize, struct IDirect3DTexture9 **texture)
753 {
754     TRACE("(%p, %p, %d, %p)\n", device, srcdata, srcdatasize, texture);
755 
756     return D3DXCreateTextureFromFileInMemoryEx(device, srcdata, srcdatasize, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
757                                                D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
758 }
759 
760 HRESULT WINAPI D3DXCreateTextureFromFileExW(struct IDirect3DDevice9 *device, const WCHAR *srcfile,
761         UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
762         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
763         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
764 {
765     void *buffer;
766     HRESULT hr;
767     DWORD size;
768 
769     TRACE("device %p, srcfile %s, width %u, height %u, miplevels %u, usage %#x, format %#x, "
770             "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n",
771             device, debugstr_w(srcfile), width, height, miplevels, usage, format,
772             pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
773 
774     if (!srcfile)
775         return D3DERR_INVALIDCALL;
776 
777     hr = map_view_of_file(srcfile, &buffer, &size);
778     if (FAILED(hr))
779         return D3DXERR_INVALIDDATA;
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, usage, 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 
1239     if (FAILED(hr)) return hr;
1240 
1241     hr = load_volume_texture_from_dds(tex, data, palette, filter, color_key, &image_info);
1242     if (FAILED(hr))
1243     {
1244         IDirect3DVolumeTexture9_Release(tex);
1245         return hr;
1246     }
1247 
1248     if (buftex)
1249     {
1250         hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, pool, &tex);
1251         if (FAILED(hr))
1252         {
1253             IDirect3DVolumeTexture9_Release(buftex);
1254             return hr;
1255         }
1256 
1257         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)buftex, (IDirect3DBaseTexture9 *)tex);
1258         IDirect3DVolumeTexture9_Release(buftex);
1259     }
1260 
1261     if (info)
1262         *info = image_info;
1263 
1264     *volume_texture = tex;
1265     return D3D_OK;
1266 }
1267 
1268 static inline void fill_texture(const struct pixel_format_desc *format, BYTE *pos, const D3DXVECTOR4 *value)
1269 {
1270     DWORD c;
1271 
1272     for (c = 0; c < format->bytes_per_pixel; c++)
1273         pos[c] = 0;
1274 
1275     for (c = 0; c < 4; c++)
1276     {
1277         float comp_value;
1278         DWORD i, v = 0, mask32 = format->bits[c] == 32 ? ~0U : ((1 << format->bits[c]) - 1);
1279 
1280         switch (c)
1281         {
1282             case 0: /* Alpha */
1283                 comp_value = value->w;
1284                 break;
1285             case 1: /* Red */
1286                 comp_value = value->x;
1287                 break;
1288             case 2: /* Green */
1289                 comp_value = value->y;
1290                 break;
1291             case 3: /* Blue */
1292                 comp_value = value->z;
1293                 break;
1294         }
1295 
1296         if (format->type == FORMAT_ARGBF16)
1297             v = float_32_to_16(comp_value);
1298         else if (format->type == FORMAT_ARGBF)
1299             v = *(DWORD *)&comp_value;
1300         else if (format->type == FORMAT_ARGB)
1301             v = comp_value * ((1 << format->bits[c]) - 1) + 0.5f;
1302         else
1303             FIXME("Unhandled format type %#x\n", format->type);
1304 
1305         for (i = 0; i < format->bits[c] + format->shift[c]; i += 8)
1306         {
1307             BYTE byte, mask;
1308 
1309             if (format->shift[c] > i)
1310             {
1311                 mask = mask32 << (format->shift[c] - i);
1312                 byte = (v << (format->shift[c] - i)) & mask;
1313             }
1314             else
1315             {
1316                 mask = mask32 >> (i - format->shift[c]);
1317                 byte = (v >> (i - format->shift[c])) & mask;
1318             }
1319             pos[i / 8] |= byte;
1320         }
1321     }
1322 }
1323 
1324 HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D function, void *funcdata)
1325 {
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 
1335     if (texture == NULL || function == NULL)
1336         return D3DERR_INVALIDCALL;
1337 
1338     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1339 
1340     for (m = 0; m < miplevels; m++)
1341     {
1342         if (FAILED(IDirect3DTexture9_GetLevelDesc(texture, m, &desc)))
1343             return D3DERR_INVALIDCALL;
1344 
1345         format = get_format_info(desc.Format);
1346         if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
1347         {
1348             FIXME("Unsupported texture format %#x\n", desc.Format);
1349             return D3DERR_INVALIDCALL;
1350         }
1351 
1352         if (FAILED(IDirect3DTexture9_LockRect(texture, m, &lock_rect, NULL, D3DLOCK_DISCARD)))
1353             return D3DERR_INVALIDCALL;
1354 
1355         size.x = 1.0f / desc.Width;
1356         size.y = 1.0f / desc.Height;
1357 
1358         data = lock_rect.pBits;
1359 
1360         for (y = 0; y < desc.Height; y++)
1361         {
1362             /* The callback function expects the coordinates of the center
1363                of the texel */
1364             coord.y = (y + 0.5f) / desc.Height;
1365 
1366             for (x = 0; x < desc.Width; x++)
1367             {
1368                 coord.x = (x + 0.5f) / desc.Width;
1369 
1370                 function(&value, &coord, &size, funcdata);
1371 
1372                 fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value);
1373             }
1374         }
1375         IDirect3DTexture9_UnlockRect(texture, m);
1376     }
1377 
1378     return D3D_OK;
1379 }
1380 
1381 HRESULT WINAPI D3DXFillTextureTX(struct IDirect3DTexture9 *texture, ID3DXTextureShader *texture_shader)
1382 {
1383     FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader);
1384     return E_NOTIMPL;
1385 }
1386 
1387 HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device,
1388                                                        const void *src_data,
1389                                                        UINT src_data_size,
1390                                                        UINT size,
1391                                                        UINT mip_levels,
1392                                                        DWORD usage,
1393                                                        D3DFORMAT format,
1394                                                        D3DPOOL pool,
1395                                                        DWORD filter,
1396                                                        DWORD mip_filter,
1397                                                        D3DCOLOR color_key,
1398                                                        D3DXIMAGE_INFO *src_info,
1399                                                        PALETTEENTRY *palette,
1400                                                        IDirect3DCubeTexture9 **cube_texture)
1401 {
1402     HRESULT hr;
1403     D3DCAPS9 caps;
1404     UINT loaded_miplevels;
1405     D3DXIMAGE_INFO img_info;
1406     BOOL dynamic_texture;
1407     BOOL file_size = FALSE;
1408     BOOL file_format = FALSE;
1409     BOOL file_mip_levels = FALSE;
1410     IDirect3DCubeTexture9 *tex, *buftex;
1411 
1412     TRACE("(%p, %p, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p)\n", device,
1413         src_data, src_data_size, size, mip_levels, usage, format, pool, filter, mip_filter,
1414         color_key, src_info, palette, cube_texture);
1415 
1416     if (!device || !cube_texture || !src_data || !src_data_size)
1417         return D3DERR_INVALIDCALL;
1418 
1419     hr = D3DXGetImageInfoFromFileInMemory(src_data, src_data_size, &img_info);
1420     if (FAILED(hr))
1421         return hr;
1422 
1423     if (img_info.ImageFileFormat != D3DXIFF_DDS)
1424         return D3DXERR_INVALIDDATA;
1425 
1426     if (img_info.Width != img_info.Height)
1427         return D3DXERR_INVALIDDATA;
1428 
1429     if (size == 0 || size == D3DX_DEFAULT_NONPOW2)
1430         size = img_info.Width;
1431     if (size == D3DX_DEFAULT)
1432         size = make_pow2(img_info.Width);
1433 
1434     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
1435         format = img_info.Format;
1436 
1437     if (size == D3DX_FROM_FILE)
1438     {
1439         file_size = TRUE;
1440         size = img_info.Width;
1441     }
1442 
1443     if (format == D3DFMT_FROM_FILE)
1444     {
1445         file_format = TRUE;
1446         format = img_info.Format;
1447     }
1448 
1449     if (mip_levels == D3DX_FROM_FILE)
1450     {
1451         file_mip_levels = TRUE;
1452         mip_levels = img_info.MipLevels;
1453     }
1454 
1455     hr = D3DXCheckCubeTextureRequirements(device, &size, &mip_levels, usage, &format, pool);
1456     if (FAILED(hr))
1457         return hr;
1458 
1459     if ((file_size && size != img_info.Width)
1460             || (file_format && format != img_info.Format)
1461             || (file_mip_levels && mip_levels != img_info.MipLevels))
1462         return D3DERR_NOTAVAILABLE;
1463 
1464     hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
1465     if (FAILED(hr))
1466         return D3DERR_INVALIDCALL;
1467 
1468     if (mip_levels > img_info.MipLevels && (D3DFMT_DXT1 <= img_info.Format && img_info.Format <= D3DFMT_DXT5))
1469     {
1470         FIXME("Generation of mipmaps for compressed pixel formats is not supported yet.\n");
1471         mip_levels = img_info.MipLevels;
1472     }
1473 
1474     dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
1475     if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
1476     {
1477         hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
1478         tex = buftex;
1479     }
1480     else
1481     {
1482         hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, pool, &tex);
1483         buftex = NULL;
1484     }
1485     if (FAILED(hr))
1486         return hr;
1487 
1488     hr = load_cube_texture_from_dds(tex, src_data, palette, filter, color_key, &img_info);
1489     if (FAILED(hr))
1490     {
1491         IDirect3DCubeTexture9_Release(tex);
1492         return hr;
1493     }
1494 
1495     loaded_miplevels = min(IDirect3DCubeTexture9_GetLevelCount(tex), img_info.MipLevels);
1496     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, palette, loaded_miplevels - 1, mip_filter);
1497     if (FAILED(hr))
1498     {
1499         IDirect3DCubeTexture9_Release(tex);
1500         return hr;
1501     }
1502 
1503     if (buftex)
1504     {
1505         hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, pool, &tex);
1506         if (FAILED(hr))
1507         {
1508             IDirect3DCubeTexture9_Release(buftex);
1509             return hr;
1510         }
1511 
1512         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)buftex, (IDirect3DBaseTexture9 *)tex);
1513         IDirect3DCubeTexture9_Release(buftex);
1514     }
1515 
1516     if (src_info)
1517         *src_info = img_info;
1518 
1519     *cube_texture = tex;
1520     return D3D_OK;
1521 }
1522 
1523 
1524 HRESULT WINAPI D3DXCreateCubeTextureFromFileA(IDirect3DDevice9 *device,
1525                                               const char *src_filename,
1526                                               IDirect3DCubeTexture9 **cube_texture)
1527 {
1528     int len;
1529     HRESULT hr;
1530     WCHAR *filename;
1531     void *data;
1532     DWORD data_size;
1533 
1534     TRACE("(%p, %s, %p): relay\n", device, wine_dbgstr_a(src_filename), cube_texture);
1535 
1536     if (!src_filename) return D3DERR_INVALIDCALL;
1537 
1538     len = MultiByteToWideChar(CP_ACP, 0, src_filename, -1, NULL, 0);
1539     filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1540     if (!filename) return E_OUTOFMEMORY;
1541     MultiByteToWideChar(CP_ACP, 0, src_filename, -1, filename, len);
1542 
1543     hr = map_view_of_file(filename, &data, &data_size);
1544     if (FAILED(hr))
1545     {
1546         HeapFree(GetProcessHeap(), 0, filename);
1547         return D3DXERR_INVALIDDATA;
1548     }
1549 
1550     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT,
1551         0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, cube_texture);
1552 
1553     UnmapViewOfFile(data);
1554     HeapFree(GetProcessHeap(), 0, filename);
1555     return hr;
1556 }
1557 
1558 HRESULT WINAPI D3DXCreateCubeTextureFromFileW(IDirect3DDevice9 *device,
1559                                               const WCHAR *src_filename,
1560                                               IDirect3DCubeTexture9 **cube_texture)
1561 {
1562     HRESULT hr;
1563     void *data;
1564     DWORD data_size;
1565 
1566     TRACE("(%p, %s, %p): relay\n", device, wine_dbgstr_w(src_filename), cube_texture);
1567 
1568     hr = map_view_of_file(src_filename, &data, &data_size);
1569     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
1570 
1571     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT,
1572         0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, cube_texture);
1573 
1574     UnmapViewOfFile(data);
1575     return hr;
1576 }
1577 
1578 HRESULT WINAPI D3DXCreateCubeTextureFromFileExA(IDirect3DDevice9 *device,
1579                                                 const char *src_filename,
1580                                                 UINT size,
1581                                                 UINT mip_levels,
1582                                                 DWORD usage,
1583                                                 D3DFORMAT format,
1584                                                 D3DPOOL pool,
1585                                                 DWORD filter,
1586                                                 DWORD mip_filter,
1587                                                 D3DCOLOR color_key,
1588                                                 D3DXIMAGE_INFO *image_info,
1589                                                 PALETTEENTRY *palette,
1590                                                 IDirect3DCubeTexture9 **cube_texture)
1591 {
1592     int len;
1593     HRESULT hr;
1594     WCHAR *filename;
1595     void *data;
1596     DWORD data_size;
1597 
1598     TRACE("(%p, %s, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n",
1599             device, wine_dbgstr_a(src_filename), size, mip_levels, usage, format,
1600             pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1601 
1602     if (!src_filename) return D3DERR_INVALIDCALL;
1603 
1604     len = MultiByteToWideChar(CP_ACP, 0, src_filename, -1, NULL, 0);
1605     filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1606     if (!filename) return E_OUTOFMEMORY;
1607     MultiByteToWideChar(CP_ACP, 0, src_filename, -1, filename, len);
1608 
1609     hr = map_view_of_file(filename, &data, &data_size);
1610     if (FAILED(hr))
1611     {
1612         HeapFree(GetProcessHeap(), 0, filename);
1613         return D3DXERR_INVALIDDATA;
1614     }
1615 
1616     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, size, mip_levels,
1617         usage, format, pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1618 
1619     UnmapViewOfFile(data);
1620     HeapFree(GetProcessHeap(), 0, filename);
1621     return hr;
1622 }
1623 
1624 HRESULT WINAPI D3DXCreateCubeTextureFromFileExW(IDirect3DDevice9 *device,
1625                                                 const WCHAR *src_filename,
1626                                                 UINT size,
1627                                                 UINT mip_levels,
1628                                                 DWORD usage,
1629                                                 D3DFORMAT format,
1630                                                 D3DPOOL pool,
1631                                                 DWORD filter,
1632                                                 DWORD mip_filter,
1633                                                 D3DCOLOR color_key,
1634                                                 D3DXIMAGE_INFO *image_info,
1635                                                 PALETTEENTRY *palette,
1636                                                 IDirect3DCubeTexture9 **cube_texture)
1637 {
1638     HRESULT hr;
1639     void *data;
1640     DWORD data_size;
1641 
1642     TRACE("(%p, %s, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n",
1643             device, wine_dbgstr_w(src_filename), size, mip_levels, usage, format,
1644             pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1645 
1646     hr = map_view_of_file(src_filename, &data, &data_size);
1647     if (FAILED(hr)) return D3DXERR_INVALIDDATA;
1648 
1649     hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, size, mip_levels,
1650         usage, format, pool, filter, mip_filter, color_key, image_info, palette, cube_texture);
1651 
1652     UnmapViewOfFile(data);
1653     return hr;
1654 }
1655 
1656 enum cube_coord
1657 {
1658     XCOORD = 0,
1659     XCOORDINV = 1,
1660     YCOORD = 2,
1661     YCOORDINV = 3,
1662     ZERO = 4,
1663     ONE = 5
1664 };
1665 
1666 static float get_cube_coord(enum cube_coord coord, unsigned int x, unsigned int y, unsigned int size)
1667 {
1668     switch (coord)
1669     {
1670         case XCOORD:
1671             return x + 0.5f;
1672         case XCOORDINV:
1673             return size - x - 0.5f;
1674         case YCOORD:
1675             return y + 0.5f;
1676         case YCOORDINV:
1677             return size - y - 0.5f;
1678         case ZERO:
1679             return 0.0f;
1680         case ONE:
1681             return size;
1682        default:
1683            ERR("Unexpected coordinate value\n");
1684            return 0.0f;
1685     }
1686 }
1687 
1688 HRESULT WINAPI D3DXFillCubeTexture(struct IDirect3DCubeTexture9 *texture, LPD3DXFILL3D function, void *funcdata)
1689 {
1690     DWORD miplevels;
1691     DWORD m, x, y, f;
1692     D3DSURFACE_DESC desc;
1693     D3DLOCKED_RECT lock_rect;
1694     D3DXVECTOR4 value;
1695     D3DXVECTOR3 coord, size;
1696     const struct pixel_format_desc *format;
1697     BYTE *data;
1698     static const enum cube_coord coordmap[6][3] =
1699         {
1700             {ONE, YCOORDINV, XCOORDINV},
1701             {ZERO, YCOORDINV, XCOORD},
1702             {XCOORD, ONE, YCOORD},
1703             {XCOORD, ZERO, YCOORDINV},
1704             {XCOORD, YCOORDINV, ONE},
1705             {XCOORDINV, YCOORDINV, ZERO}
1706         };
1707 
1708     if (texture == NULL || function == NULL)
1709         return D3DERR_INVALIDCALL;
1710 
1711     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1712 
1713     for (m = 0; m < miplevels; m++)
1714     {
1715         if (FAILED(IDirect3DCubeTexture9_GetLevelDesc(texture, m, &desc)))
1716             return D3DERR_INVALIDCALL;
1717 
1718         format = get_format_info(desc.Format);
1719         if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
1720         {
1721             FIXME("Unsupported texture format %#x\n", desc.Format);
1722             return D3DERR_INVALIDCALL;
1723         }
1724 
1725         for (f = 0; f < 6; f++)
1726         {
1727             if (FAILED(IDirect3DCubeTexture9_LockRect(texture, f, m, &lock_rect, NULL, D3DLOCK_DISCARD)))
1728                 return D3DERR_INVALIDCALL;
1729 
1730             size.x = (f == 0) || (f == 1) ? 0.0f : 2.0f / desc.Width;
1731             size.y = (f == 2) || (f == 3) ? 0.0f : 2.0f / desc.Width;
1732             size.z = (f == 4) || (f == 5) ? 0.0f : 2.0f / desc.Width;
1733 
1734             data = lock_rect.pBits;
1735 
1736             for (y = 0; y < desc.Height; y++)
1737             {
1738                 for (x = 0; x < desc.Width; x++)
1739                 {
1740                     coord.x = get_cube_coord(coordmap[f][0], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1741                     coord.y = get_cube_coord(coordmap[f][1], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1742                     coord.z = get_cube_coord(coordmap[f][2], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1743 
1744                     function(&value, &coord, &size, funcdata);
1745 
1746                     fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value);
1747                 }
1748             }
1749             IDirect3DCubeTexture9_UnlockRect(texture, f, m);
1750         }
1751     }
1752 
1753     return D3D_OK;
1754 }
1755 
1756 HRESULT WINAPI D3DXFillCubeTextureTX(struct IDirect3DCubeTexture9 *texture, ID3DXTextureShader *texture_shader)
1757 {
1758     FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader);
1759     return E_NOTIMPL;
1760 }
1761 
1762 HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LPD3DXFILL3D function, void *funcdata)
1763 {
1764     DWORD miplevels;
1765     DWORD m, x, y, z;
1766     D3DVOLUME_DESC desc;
1767     D3DLOCKED_BOX lock_box;
1768     D3DXVECTOR4 value;
1769     D3DXVECTOR3 coord, size;
1770     const struct pixel_format_desc *format;
1771     BYTE *data;
1772 
1773     if (texture == NULL || function == NULL)
1774         return D3DERR_INVALIDCALL;
1775 
1776     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1777 
1778     for (m = 0; m < miplevels; m++)
1779     {
1780         if (FAILED(IDirect3DVolumeTexture9_GetLevelDesc(texture, m, &desc)))
1781             return D3DERR_INVALIDCALL;
1782 
1783         format = get_format_info(desc.Format);
1784         if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF)
1785         {
1786             FIXME("Unsupported texture format %#x\n", desc.Format);
1787             return D3DERR_INVALIDCALL;
1788         }
1789 
1790         if (FAILED(IDirect3DVolumeTexture9_LockBox(texture, m, &lock_box, NULL, D3DLOCK_DISCARD)))
1791             return D3DERR_INVALIDCALL;
1792 
1793         size.x = 1.0f / desc.Width;
1794         size.y = 1.0f / desc.Height;
1795         size.z = 1.0f / desc.Depth;
1796 
1797         data = lock_box.pBits;
1798 
1799         for (z = 0; z < desc.Depth; z++)
1800         {
1801             /* The callback function expects the coordinates of the center
1802                of the texel */
1803             coord.z = (z + 0.5f) / desc.Depth;
1804 
1805             for (y = 0; y < desc.Height; y++)
1806             {
1807                 coord.y = (y + 0.5f) / desc.Height;
1808 
1809                 for (x = 0; x < desc.Width; x++)
1810                 {
1811                     coord.x = (x + 0.5f) / desc.Width;
1812 
1813                     function(&value, &coord, &size, funcdata);
1814 
1815                     fill_texture(format, data + z * lock_box.SlicePitch + y * lock_box.RowPitch
1816                             + x * format->bytes_per_pixel, &value);
1817                 }
1818             }
1819         }
1820         IDirect3DVolumeTexture9_UnlockBox(texture, m);
1821     }
1822 
1823     return D3D_OK;
1824 }
1825 
1826 HRESULT WINAPI D3DXFillVolumeTextureTX(struct IDirect3DVolumeTexture9 *texture, ID3DXTextureShader *texture_shader)
1827 {
1828     FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader);
1829     return E_NOTIMPL;
1830 }
1831 
1832 HRESULT WINAPI D3DXSaveTextureToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1833         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
1834 {
1835     int len;
1836     WCHAR *filename;
1837     HRESULT hr;
1838     ID3DXBuffer *buffer;
1839 
1840     TRACE("(%s, %#x, %p, %p): relay\n",
1841             wine_dbgstr_a(dst_filename), file_format, src_texture, src_palette);
1842 
1843     if (!dst_filename) return D3DERR_INVALIDCALL;
1844 
1845     len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0);
1846     filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1847     if (!filename) return E_OUTOFMEMORY;
1848     MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len);
1849 
1850     hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, src_texture, src_palette);
1851     if (SUCCEEDED(hr))
1852     {
1853         hr = write_buffer_to_file(filename, buffer);
1854         ID3DXBuffer_Release(buffer);
1855     }
1856 
1857     HeapFree(GetProcessHeap(), 0, filename);
1858     return hr;
1859 }
1860 
1861 HRESULT WINAPI D3DXSaveTextureToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
1862         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
1863 {
1864     HRESULT hr;
1865     ID3DXBuffer *buffer;
1866 
1867     TRACE("(%s, %#x, %p, %p): relay\n",
1868         wine_dbgstr_w(dst_filename), file_format, src_texture, src_palette);
1869 
1870     if (!dst_filename) return D3DERR_INVALIDCALL;
1871 
1872     hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, src_texture, src_palette);
1873     if (SUCCEEDED(hr))
1874     {
1875         hr = write_buffer_to_file(dst_filename, buffer);
1876         ID3DXBuffer_Release(buffer);
1877     }
1878 
1879     return hr;
1880 }
1881 
1882 HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format,
1883         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
1884 {
1885     HRESULT hr;
1886     D3DRESOURCETYPE type;
1887     IDirect3DSurface9 *surface;
1888 
1889     TRACE("(%p, %#x, %p, %p)\n",
1890         dst_buffer, file_format, src_texture, src_palette);
1891 
1892     if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL;
1893 
1894     if (file_format == D3DXIFF_DDS)
1895         return save_dds_texture_to_memory(dst_buffer, src_texture, src_palette);
1896 
1897     type = IDirect3DBaseTexture9_GetType(src_texture);
1898     switch (type)
1899     {
1900         case D3DRTYPE_TEXTURE:
1901         case D3DRTYPE_CUBETEXTURE:
1902             hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface);
1903             break;
1904         case D3DRTYPE_VOLUMETEXTURE:
1905             FIXME("Volume textures aren't supported yet\n");
1906             return E_NOTIMPL;
1907         default:
1908             return D3DERR_INVALIDCALL;
1909     }
1910 
1911     if (SUCCEEDED(hr))
1912     {
1913         hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL);
1914         IDirect3DSurface9_Release(surface);
1915     }
1916 
1917     return hr;
1918 }
1919 
1920 HRESULT WINAPI D3DXComputeNormalMap(IDirect3DTexture9 *texture, IDirect3DTexture9 *src_texture,
1921         const PALETTEENTRY *src_palette, DWORD flags, DWORD channel, float amplitude)
1922 {
1923     FIXME("texture %p, src_texture %p, src_palette %p, flags %#x, channel %u, amplitude %.8e stub.\n",
1924             texture, src_texture, src_palette, flags, channel, amplitude);
1925 
1926     return D3D_OK;
1927 }
1928