d3dx9/tests: Add basic tests for D3DXCreateText.
[wine] / dlls / d3dx9_36 / texture.c
1 /*
2  * Copyright 2009 Tony Wasserka
3  * Copyright 2010 Christian Costa
4  * Copyright 2010 Owen Rudge for CodeWeavers
5  * Copyright 2010 Matteo Bruni for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "wine/unicode.h"
23 #include "wine/debug.h"
24 #include "d3dx9_36_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
27
28 /* Returns TRUE if num is a power of 2, FALSE if not, or if 0 */
29 static BOOL is_pow2(UINT num)
30 {
31     return !(num & (num - 1));
32 }
33
34 /* Returns the smallest power of 2 which is greater than or equal to num */
35 static UINT make_pow2(UINT num)
36 {
37     UINT result = 1;
38
39     /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */
40     if (num >= 0x80000000)
41         return 0x80000000;
42
43     while (result < num)
44         result <<= 1;
45
46     return result;
47 }
48
49 static HRESULT get_surface(D3DRESOURCETYPE type, LPDIRECT3DBASETEXTURE9 tex,
50                            int face, UINT level, LPDIRECT3DSURFACE9 *surf)
51 {
52     switch (type)
53     {
54         case D3DRTYPE_TEXTURE:
55             return IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) tex, level, surf);
56         case D3DRTYPE_CUBETEXTURE:
57             return IDirect3DCubeTexture9_GetCubeMapSurface((IDirect3DCubeTexture9*) tex, face, level, surf);
58         default:
59             ERR("Unexpected texture type\n");
60             return E_NOTIMPL;
61     }
62 }
63
64 HRESULT WINAPI D3DXFilterTexture(LPDIRECT3DBASETEXTURE9 texture,
65                                  CONST PALETTEENTRY *palette,
66                                  UINT srclevel,
67                                  DWORD filter)
68 {
69     UINT level;
70     HRESULT hr;
71     D3DRESOURCETYPE type;
72
73     TRACE("(%p, %p, %d, %d)\n", texture, palette, srclevel, filter);
74
75     if (!texture)
76         return D3DERR_INVALIDCALL;
77
78     if ((filter & 0xFFFF) > D3DX_FILTER_BOX && filter != D3DX_DEFAULT)
79         return D3DERR_INVALIDCALL;
80
81     if (srclevel >= IDirect3DBaseTexture9_GetLevelCount(texture))
82         return D3DERR_INVALIDCALL;
83
84     switch (type = IDirect3DBaseTexture9_GetType(texture))
85     {
86         case D3DRTYPE_TEXTURE:
87         case D3DRTYPE_CUBETEXTURE:
88         {
89             IDirect3DSurface9 *topsurf, *mipsurf;
90             D3DSURFACE_DESC desc;
91             int i, numfaces;
92
93             if (type == D3DRTYPE_TEXTURE)
94             {
95                 numfaces = 1;
96                 IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
97             }
98             else
99             {
100                 numfaces = 6;
101                 IDirect3DCubeTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
102             }
103
104             if (filter == D3DX_DEFAULT)
105             {
106                 if (is_pow2(desc.Width) && is_pow2(desc.Height))
107                     filter = D3DX_FILTER_BOX;
108                 else
109                     filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER;
110             }
111
112             for (i = 0; i < numfaces; i++)
113             {
114                 level = srclevel + 1;
115                 hr = get_surface(type, texture, i, srclevel, &topsurf);
116
117                 if (FAILED(hr))
118                     return D3DERR_INVALIDCALL;
119
120                 while (get_surface(type, texture, i, level, &mipsurf) == D3D_OK)
121                 {
122                     hr = D3DXLoadSurfaceFromSurface(mipsurf, palette, NULL, topsurf, palette, NULL, filter, 0);
123                     IDirect3DSurface9_Release(topsurf);
124                     topsurf = mipsurf;
125
126                     if (FAILED(hr))
127                         break;
128
129                     level++;
130                 }
131
132                 IDirect3DSurface9_Release(topsurf);
133                 if (FAILED(hr))
134                     return hr;
135             }
136
137             return D3D_OK;
138         }
139
140         default:
141             FIXME("Implement volume texture filtering\n");
142             return E_NOTIMPL;
143     }
144 }
145
146 HRESULT WINAPI D3DXCheckTextureRequirements(LPDIRECT3DDEVICE9 device,
147                                             UINT* width,
148                                             UINT* height,
149                                             UINT* miplevels,
150                                             DWORD usage,
151                                             D3DFORMAT* format,
152                                             D3DPOOL pool)
153 {
154     UINT w = (width && *width) ? *width : 1;
155     UINT h = (height && *height) ? *height : 1;
156     D3DCAPS9 caps;
157     D3DDEVICE_CREATION_PARAMETERS params;
158     IDirect3D9 *d3d = NULL;
159     D3DDISPLAYMODE mode;
160     HRESULT hr;
161     D3DFORMAT usedformat = D3DFMT_UNKNOWN;
162
163     TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool);
164
165     if (!device)
166         return D3DERR_INVALIDCALL;
167
168     /* usage */
169     if (usage == D3DX_DEFAULT)
170         usage = 0;
171     if (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES))
172         return D3DERR_INVALIDCALL;
173
174     /* pool */
175     if ((pool != D3DPOOL_DEFAULT) && (pool != D3DPOOL_MANAGED) && (pool != D3DPOOL_SYSTEMMEM) && (pool != D3DPOOL_SCRATCH))
176         return D3DERR_INVALIDCALL;
177
178     /* width and height */
179     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
180         return D3DERR_INVALIDCALL;
181
182     /* 256 x 256 default width/height */
183     if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT))
184         w = h = 256;
185     else if (w == D3DX_DEFAULT)
186         w = (height ? h : 256);
187     else if (h == D3DX_DEFAULT)
188         h = (width ? w : 256);
189
190     /* ensure width/height is power of 2 */
191     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w)))
192         w = make_pow2(w);
193
194     if (w > caps.MaxTextureWidth)
195         w = caps.MaxTextureWidth;
196
197     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h)))
198         h = make_pow2(h);
199
200     if (h > caps.MaxTextureHeight)
201         h = caps.MaxTextureHeight;
202
203     /* texture must be square? */
204     if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
205     {
206         if (w > h)
207             h = w;
208         else
209             w = h;
210     }
211
212     if (width)
213         *width = w;
214
215     if (height)
216         *height = h;
217
218     /* miplevels */
219     if (miplevels)
220     {
221         UINT max_mipmaps = 1;
222
223         if (!width && !height)
224             max_mipmaps = 9;    /* number of mipmaps in a 256x256 texture */
225         else
226         {
227             UINT max_dimen = max(w, h);
228
229             while (max_dimen > 1)
230             {
231                 max_dimen >>= 1;
232                 max_mipmaps++;
233             }
234         }
235
236         if (*miplevels == 0 || *miplevels > max_mipmaps)
237             *miplevels = max_mipmaps;
238     }
239
240     /* format */
241     if (format)
242     {
243         TRACE("Requested format %x\n", *format);
244         usedformat = *format;
245     }
246
247     hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
248
249     if (FAILED(hr))
250         goto cleanup;
251
252     hr = IDirect3DDevice9_GetCreationParameters(device, &params);
253
254     if (FAILED(hr))
255         goto cleanup;
256
257     hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
258
259     if (FAILED(hr))
260         goto cleanup;
261
262     if ((usedformat == D3DFMT_UNKNOWN) || (usedformat == D3DX_DEFAULT))
263         usedformat = D3DFMT_A8R8G8B8;
264
265     hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format,
266         usage, D3DRTYPE_TEXTURE, usedformat);
267
268     if (FAILED(hr))
269     {
270         /* Heuristic to choose the fallback format */
271         const PixelFormatDesc *fmt = get_format_info(usedformat);
272         BOOL allow_24bits;
273         int bestscore = INT_MIN, i = 0, j;
274         unsigned int channels;
275         const PixelFormatDesc *curfmt;
276
277         if (!fmt)
278         {
279             FIXME("Pixel format %x not handled\n", usedformat);
280             goto cleanup;
281         }
282
283         allow_24bits = fmt->bytes_per_pixel == 3;
284         channels = (fmt->bits[0] ? 1 : 0) + (fmt->bits[1] ? 1 : 0)
285             + (fmt->bits[2] ? 1 : 0) + (fmt->bits[3] ? 1 : 0);
286         usedformat = D3DFMT_UNKNOWN;
287
288         while ((curfmt = get_format_info_idx(i)))
289         {
290             unsigned int curchannels = (curfmt->bits[0] ? 1 : 0) + (curfmt->bits[1] ? 1 : 0)
291                 + (curfmt->bits[2] ? 1 : 0) + (curfmt->bits[3] ? 1 : 0);
292             int score;
293
294             i++;
295
296             if (curchannels < channels)
297                 continue;
298             if (curfmt->bytes_per_pixel == 3 && !allow_24bits)
299                 continue;
300
301             hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType,
302                 mode.Format, usage, D3DRTYPE_TEXTURE, curfmt->format);
303             if (FAILED(hr))
304                 continue;
305
306             /* This format can be used, let's evaluate it.
307                Weights chosen quite arbitrarily... */
308             score = 16 - 4 * (curchannels - channels);
309
310             for (j = 0; j < 4; j++)
311             {
312                 int diff = curfmt->bits[j] - fmt->bits[j];
313                 score += 16 - (diff < 0 ? -diff * 4 : diff);
314             }
315
316             if (score > bestscore)
317             {
318                 bestscore = score;
319                 usedformat = curfmt->format;
320             }
321         }
322         hr = D3D_OK;
323     }
324
325 cleanup:
326
327     if (d3d)
328         IDirect3D9_Release(d3d);
329
330     if (FAILED(hr))
331         return hr;
332
333     if (usedformat == D3DFMT_UNKNOWN)
334     {
335         WARN("Couldn't find a suitable pixel format\n");
336         return D3DERR_NOTAVAILABLE;
337     }
338
339     TRACE("Format chosen: %x\n", usedformat);
340     if (format)
341         *format = usedformat;
342
343     return D3D_OK;
344 }
345
346 HRESULT WINAPI D3DXCheckCubeTextureRequirements(LPDIRECT3DDEVICE9 device,
347                                                 UINT *size,
348                                                 UINT *miplevels,
349                                                 DWORD usage,
350                                                 D3DFORMAT *format,
351                                                 D3DPOOL pool)
352 {
353     D3DCAPS9 caps;
354     UINT s = (size && *size) ? *size : 256;
355     HRESULT hr;
356
357     TRACE("(%p, %p, %p, %u, %p, %u)\n", device, size, miplevels, usage, format, pool);
358
359     if (s == D3DX_DEFAULT)
360         s = 256;
361
362     if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
363         return D3DERR_INVALIDCALL;
364
365     if (!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP))
366         return D3DERR_NOTAVAILABLE;
367
368     /* ensure width/height is power of 2 */
369     if ((caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && (!is_pow2(s)))
370         s = make_pow2(s);
371
372     hr = D3DXCheckTextureRequirements(device, &s, &s, miplevels, usage, format, pool);
373
374     if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP))
375     {
376         if(miplevels)
377             *miplevels = 1;
378     }
379
380     if (size)
381         *size = s;
382
383     return hr;
384 }
385
386 HRESULT WINAPI D3DXCheckVolumeTextureRequirements(LPDIRECT3DDEVICE9 device,
387                                                   UINT *width,
388                                                   UINT *height,
389                                                   UINT *depth,
390                                                   UINT *miplevels,
391                                                   DWORD usage,
392                                                   D3DFORMAT *format,
393                                                   D3DPOOL pool)
394 {
395     D3DCAPS9 caps;
396     UINT w = width ? *width : D3DX_DEFAULT;
397     UINT h = height ? *height : D3DX_DEFAULT;
398     UINT d = (depth && *depth) ? *depth : 1;
399     HRESULT hr;
400
401     TRACE("(%p, %p, %p, %p, %p, %u, %p, %u)\n", device, width, height, depth, miplevels,
402           usage, format, pool);
403
404     if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
405         return D3DERR_INVALIDCALL;
406
407     if (!(caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP))
408         return D3DERR_NOTAVAILABLE;
409
410     hr = D3DXCheckTextureRequirements(device, &w, &h, NULL, usage, format, pool);
411     if (d == D3DX_DEFAULT)
412         d = 1;
413
414     /* ensure width/height is power of 2 */
415     if ((caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) &&
416         (!is_pow2(w) || !is_pow2(h) || !is_pow2(d)))
417     {
418         w = make_pow2(w);
419         h = make_pow2(h);
420         d = make_pow2(d);
421     }
422
423     if (w > caps.MaxVolumeExtent)
424         w = caps.MaxVolumeExtent;
425     if (h > caps.MaxVolumeExtent)
426         h = caps.MaxVolumeExtent;
427     if (d > caps.MaxVolumeExtent)
428         d = caps.MaxVolumeExtent;
429
430     if (miplevels)
431     {
432         if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP))
433             *miplevels = 1;
434         else
435         {
436             UINT max_mipmaps = 1;
437             UINT max_dimen = max(max(w, h), d);
438
439             while (max_dimen > 1)
440             {
441                 max_dimen >>= 1;
442                 max_mipmaps++;
443             }
444
445             if (*miplevels == 0 || *miplevels > max_mipmaps)
446                 *miplevels = max_mipmaps;
447         }
448     }
449
450     if (width)
451         *width = w;
452     if (height)
453         *height = h;
454     if (depth)
455         *depth = d;
456
457     return hr;
458 }
459
460 HRESULT WINAPI D3DXCreateTexture(LPDIRECT3DDEVICE9 pDevice,
461                                  UINT width,
462                                  UINT height,
463                                  UINT miplevels,
464                                  DWORD usage,
465                                  D3DFORMAT format,
466                                  D3DPOOL pool,
467                                  LPDIRECT3DTEXTURE9 *ppTexture)
468 {
469     HRESULT hr;
470
471     TRACE("(%p, %u, %u, %u, %x, %x, %x, %p)\n", pDevice, width, height, miplevels, usage, format,
472         pool, ppTexture);
473
474     if (!pDevice || !ppTexture)
475         return D3DERR_INVALIDCALL;
476
477     hr = D3DXCheckTextureRequirements(pDevice, &width, &height, &miplevels, usage, &format, pool);
478
479     if (FAILED(hr))
480         return hr;
481
482     return IDirect3DDevice9_CreateTexture(pDevice, width, height, miplevels, usage, format, pool, ppTexture, NULL);
483 }
484
485 HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(LPDIRECT3DDEVICE9 device,
486                                                    LPCVOID srcdata,
487                                                    UINT srcdatasize,
488                                                    UINT width,
489                                                    UINT height,
490                                                    UINT miplevels,
491                                                    DWORD usage,
492                                                    D3DFORMAT format,
493                                                    D3DPOOL pool,
494                                                    DWORD filter,
495                                                    DWORD mipfilter,
496                                                    D3DCOLOR colorkey,
497                                                    D3DXIMAGE_INFO* srcinfo,
498                                                    PALETTEENTRY* palette,
499                                                    LPDIRECT3DTEXTURE9* texture)
500 {
501     IDirect3DTexture9 **texptr;
502     IDirect3DTexture9 *buftex;
503     IDirect3DSurface9 *surface;
504     BOOL file_width = FALSE, file_height = FALSE;
505     BOOL file_format = FALSE, file_miplevels = FALSE;
506     D3DXIMAGE_INFO imginfo;
507     D3DCAPS9 caps;
508     HRESULT hr;
509
510     TRACE("(%p, %p, %u, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p)\n", device, srcdata, srcdatasize, width,
511         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
512
513     /* check for invalid parameters */
514     if (!device || !texture || !srcdata || !srcdatasize)
515         return D3DERR_INVALIDCALL;
516
517     hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo);
518
519     if (FAILED(hr))
520     {
521         *texture = NULL;
522         return hr;
523     }
524
525     /* handle default values */
526     if (width == 0 || width == D3DX_DEFAULT_NONPOW2)
527         width = imginfo.Width;
528
529     if (height == 0 || height == D3DX_DEFAULT_NONPOW2)
530         height = imginfo.Height;
531
532     if (width == D3DX_DEFAULT)
533         width = make_pow2(imginfo.Width);
534
535     if (height == D3DX_DEFAULT)
536         height = make_pow2(imginfo.Height);
537
538     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
539         format = imginfo.Format;
540
541     if (width == D3DX_FROM_FILE)
542     {
543         file_width = TRUE;
544         width = imginfo.Width;
545     }
546
547     if (height == D3DX_FROM_FILE)
548     {
549         file_height = TRUE;
550         height = imginfo.Height;
551     }
552
553     if (format == D3DFMT_FROM_FILE)
554     {
555         file_format = TRUE;
556         format = imginfo.Format;
557     }
558
559     if (miplevels == D3DX_FROM_FILE)
560     {
561         file_miplevels = TRUE;
562         miplevels = imginfo.MipLevels;
563     }
564
565     /* fix texture creation parameters */
566     hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
567
568     if (FAILED(hr))
569     {
570         *texture = NULL;
571         return hr;
572     }
573
574     if (((file_width) && (width != imginfo.Width))    ||
575         ((file_height) && (height != imginfo.Height)) ||
576         ((file_format) && (format != imginfo.Format)) ||
577         ((file_miplevels) && (miplevels != imginfo.MipLevels)))
578     {
579         return D3DERR_NOTAVAILABLE;
580     }
581
582     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
583         return D3DERR_INVALIDCALL;
584
585     /* Create the to-be-filled texture */
586     if ((caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (pool != D3DPOOL_DEFAULT) && (usage != D3DUSAGE_DYNAMIC))
587     {
588         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
589         texptr = texture;
590     }
591     else
592     {
593         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
594         texptr = &buftex;
595     }
596
597     if (FAILED(hr))
598     {
599         *texture = NULL;
600         return hr;
601     }
602
603     /* Load the file */
604     IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface);
605     hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL);
606     IDirect3DSurface9_Release(surface);
607
608     if (FAILED(hr))
609     {
610         IDirect3DTexture9_Release(*texptr);
611         *texture = NULL;
612         return hr;
613     }
614
615     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, 0, mipfilter);
616
617     if (FAILED(hr))
618     {
619         IDirect3DTexture9_Release(*texptr);
620         *texture = NULL;
621         return hr;
622     }
623
624     /* Move the data to the actual texture if necessary */
625     if (texptr == &buftex)
626     {
627         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
628
629         if (FAILED(hr))
630         {
631             IDirect3DTexture9_Release(buftex);
632             *texture = NULL;
633             return hr;
634         }
635
636         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)buftex, (IDirect3DBaseTexture9*)(*texture));
637         IDirect3DTexture9_Release(buftex);
638     }
639
640     if (srcinfo)
641         *srcinfo = imginfo;
642
643     return D3D_OK;
644 }
645
646 HRESULT WINAPI D3DXCreateTextureFromFileInMemory(LPDIRECT3DDEVICE9 device,
647                                                  LPCVOID srcdata,
648                                                  UINT srcdatasize,
649                                                  LPDIRECT3DTEXTURE9 *texture)
650 {
651     TRACE("(%p, %p, %d, %p)\n", device, srcdata, srcdatasize, texture);
652
653     return D3DXCreateTextureFromFileInMemoryEx(device, srcdata, srcdatasize, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
654                                                D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
655 }
656
657 HRESULT WINAPI D3DXCreateTextureFromFileExW(LPDIRECT3DDEVICE9 device,
658                                             LPCWSTR srcfile,
659                                             UINT width,
660                                             UINT height,
661                                             UINT miplevels,
662                                             DWORD usage,
663                                             D3DFORMAT format,
664                                             D3DPOOL pool,
665                                             DWORD filter,
666                                             DWORD mipfilter,
667                                             D3DCOLOR colorkey,
668                                             D3DXIMAGE_INFO *srcinfo,
669                                             PALETTEENTRY *palette,
670                                             LPDIRECT3DTEXTURE9 *texture)
671 {
672     HRESULT hr;
673     DWORD size;
674     LPVOID buffer;
675
676     TRACE("(%p, %p, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n", device, debugstr_w(srcfile), width,
677         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
678
679     if (!srcfile)
680         return D3DERR_INVALIDCALL;
681
682     hr = map_view_of_file(srcfile, &buffer, &size);
683     if (FAILED(hr))
684         return D3DXERR_INVALIDDATA;
685
686     hr = D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width, height, miplevels, usage, format, pool,
687         filter, mipfilter, colorkey, srcinfo, palette, texture);
688
689     UnmapViewOfFile(buffer);
690
691     return hr;
692 }
693
694 HRESULT WINAPI D3DXCreateTextureFromFileExA(LPDIRECT3DDEVICE9 device,
695                                             LPCSTR srcfile,
696                                             UINT width,
697                                             UINT height,
698                                             UINT miplevels,
699                                             DWORD usage,
700                                             D3DFORMAT format,
701                                             D3DPOOL pool,
702                                             DWORD filter,
703                                             DWORD mipfilter,
704                                             D3DCOLOR colorkey,
705                                             D3DXIMAGE_INFO *srcinfo,
706                                             PALETTEENTRY *palette,
707                                             LPDIRECT3DTEXTURE9 *texture)
708 {
709     LPWSTR widename;
710     HRESULT hr;
711     DWORD len;
712
713     TRACE("(%p, %p, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n", device, debugstr_a(srcfile), width,
714         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
715
716     if (!device || !srcfile || !texture)
717         return D3DERR_INVALIDCALL;
718
719     len = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
720     widename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
721     MultiByteToWideChar(CP_ACP, 0, srcfile, -1, widename, len);
722
723     hr = D3DXCreateTextureFromFileExW(device, widename, width, height, miplevels,
724                                       usage, format, pool, filter, mipfilter,
725                                       colorkey, srcinfo, palette, texture);
726
727     HeapFree(GetProcessHeap(), 0, widename);
728     return hr;
729 }
730
731 HRESULT WINAPI D3DXCreateTextureFromFileA(LPDIRECT3DDEVICE9 device,
732                                           LPCSTR srcfile,
733                                           LPDIRECT3DTEXTURE9 *texture)
734 {
735     TRACE("(%p, %s, %p)\n", device, debugstr_a(srcfile), texture);
736
737     return D3DXCreateTextureFromFileExA(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
738                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
739 }
740
741 HRESULT WINAPI D3DXCreateTextureFromFileW(LPDIRECT3DDEVICE9 device,
742                                           LPCWSTR srcfile,
743                                           LPDIRECT3DTEXTURE9 *texture)
744 {
745     TRACE("(%p, %s, %p)\n", device, debugstr_w(srcfile), texture);
746
747     return D3DXCreateTextureFromFileExW(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
748                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
749 }
750
751
752 HRESULT WINAPI D3DXCreateTextureFromResourceA(LPDIRECT3DDEVICE9 device,
753                                               HMODULE srcmodule,
754                                               LPCSTR resource,
755                                               LPDIRECT3DTEXTURE9 *texture)
756 {
757     TRACE("(%p, %s): relay\n", srcmodule, debugstr_a(resource));
758
759     return D3DXCreateTextureFromResourceExA(device, srcmodule, resource, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
760                                             D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
761 }
762
763 HRESULT WINAPI D3DXCreateTextureFromResourceW(LPDIRECT3DDEVICE9 device,
764                                               HMODULE srcmodule,
765                                               LPCWSTR resource,
766                                               LPDIRECT3DTEXTURE9 *texture)
767 {
768     TRACE("(%p, %s): relay\n", srcmodule, debugstr_w(resource));
769
770     return D3DXCreateTextureFromResourceExW(device, srcmodule, resource, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
771                                             D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
772 }
773
774 HRESULT WINAPI D3DXCreateTextureFromResourceExA(LPDIRECT3DDEVICE9 device,
775                                                 HMODULE srcmodule,
776                                                 LPCSTR resource,
777                                                 UINT width,
778                                                 UINT height,
779                                                 UINT miplevels,
780                                                 DWORD usage,
781                                                 D3DFORMAT format,
782                                                 D3DPOOL pool,
783                                                 DWORD filter,
784                                                 DWORD mipfilter,
785                                                 D3DCOLOR colorkey,
786                                                 D3DXIMAGE_INFO *srcinfo,
787                                                 PALETTEENTRY *palette,
788                                                 LPDIRECT3DTEXTURE9 *texture)
789 {
790     HRSRC resinfo;
791
792     TRACE("(%p, %s): relay\n", srcmodule, debugstr_a(resource));
793
794     if (!device || !texture)
795         return D3DERR_INVALIDCALL;
796
797     resinfo = FindResourceA(srcmodule, resource, (LPCSTR) RT_RCDATA);
798
799     if (resinfo)
800     {
801         LPVOID buffer;
802         HRESULT hr;
803         DWORD size;
804
805         hr = load_resource_into_memory(srcmodule, resinfo, &buffer, &size);
806
807         if (FAILED(hr))
808             return D3DXERR_INVALIDDATA;
809
810         return D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width,
811                                                    height, miplevels, usage, format,
812                                                    pool, filter, mipfilter, colorkey,
813                                                    srcinfo, palette, texture);
814     }
815
816     /* Try loading the resource as bitmap data */
817     resinfo = FindResourceA(srcmodule, resource, (LPCSTR) RT_BITMAP);
818
819     if (resinfo)
820     {
821         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
822         return E_NOTIMPL;
823     }
824
825     return D3DXERR_INVALIDDATA;
826 }
827
828 HRESULT WINAPI D3DXCreateTextureFromResourceExW(LPDIRECT3DDEVICE9 device,
829                                                 HMODULE srcmodule,
830                                                 LPCWSTR resource,
831                                                 UINT width,
832                                                 UINT height,
833                                                 UINT miplevels,
834                                                 DWORD usage,
835                                                 D3DFORMAT format,
836                                                 D3DPOOL pool,
837                                                 DWORD filter,
838                                                 DWORD mipfilter,
839                                                 D3DCOLOR colorkey,
840                                                 D3DXIMAGE_INFO *srcinfo,
841                                                 PALETTEENTRY *palette,
842                                                 LPDIRECT3DTEXTURE9 *texture)
843 {
844     HRSRC resinfo;
845
846     TRACE("(%p, %s): relay\n", srcmodule, debugstr_w(resource));
847
848     if (!device || !texture)
849         return D3DERR_INVALIDCALL;
850
851     resinfo = FindResourceW(srcmodule, resource, (LPCWSTR) RT_RCDATA);
852
853     if (resinfo)
854     {
855         LPVOID buffer;
856         HRESULT hr;
857         DWORD size;
858
859         hr = load_resource_into_memory(srcmodule, resinfo, &buffer, &size);
860
861         if (FAILED(hr))
862             return D3DXERR_INVALIDDATA;
863
864         return D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width,
865                                                    height, miplevels, usage, format,
866                                                    pool, filter, mipfilter, colorkey,
867                                                    srcinfo, palette, texture);
868     }
869
870     /* Try loading the resource as bitmap data */
871     resinfo = FindResourceW(srcmodule, resource, (LPCWSTR) RT_BITMAP);
872
873     if (resinfo)
874     {
875         FIXME("Implement loading bitmaps from resource type RT_BITMAP\n");
876         return E_NOTIMPL;
877     }
878
879     return D3DXERR_INVALIDDATA;
880 }
881
882 HRESULT WINAPI D3DXCreateCubeTexture(LPDIRECT3DDEVICE9 device,
883                                      UINT size,
884                                      UINT miplevels,
885                                      DWORD usage,
886                                      D3DFORMAT format,
887                                      D3DPOOL pool,
888                                      LPDIRECT3DCUBETEXTURE9 *texture)
889 {
890     HRESULT hr;
891
892     TRACE("(%p, %u, %u, %#x, %#x, %#x, %p)\n", device, size, miplevels, usage, format,
893         pool, texture);
894
895     if (!device || !texture)
896         return D3DERR_INVALIDCALL;
897
898     hr = D3DXCheckCubeTextureRequirements(device, &size, &miplevels, usage, &format, pool);
899
900     if (FAILED(hr))
901     {
902         TRACE("D3DXCheckCubeTextureRequirements failed\n");
903         return hr;
904     }
905
906     return IDirect3DDevice9_CreateCubeTexture(device, size, miplevels, usage, format, pool, texture, NULL);
907 }
908
909 HRESULT WINAPI D3DXCreateVolumeTexture(LPDIRECT3DDEVICE9 device,
910                                        UINT width,
911                                        UINT height,
912                                        UINT depth,
913                                        UINT miplevels,
914                                        DWORD usage,
915                                        D3DFORMAT format,
916                                        D3DPOOL pool,
917                                        LPDIRECT3DVOLUMETEXTURE9 *texture)
918 {
919     HRESULT hr;
920
921     TRACE("(%p, %u, %u, %u, %u, %#x, %#x, %#x, %p)\n", device, width, height, depth,
922           miplevels, usage, format, pool, texture);
923
924     if (!device || !texture)
925         return D3DERR_INVALIDCALL;
926
927     hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth,
928                                             &miplevels, usage, &format, pool);
929
930     if (FAILED(hr))
931     {
932         TRACE("D3DXCheckVolumeTextureRequirements failed\n");
933         return hr;
934     }
935
936     return IDirect3DDevice9_CreateVolumeTexture(device, width, height, depth, miplevels,
937                                                 usage, format, pool, texture, NULL);
938 }
939
940 HRESULT WINAPI D3DXFillTexture(LPDIRECT3DTEXTURE9 texture,
941                                LPD3DXFILL2D function,
942                                LPVOID funcdata)
943 {
944     DWORD miplevels;
945     DWORD m, i, x, y, c, v;
946     D3DSURFACE_DESC desc;
947     D3DLOCKED_RECT lock_rect;
948     D3DXVECTOR4 value;
949     D3DXVECTOR2 coord, size;
950     const PixelFormatDesc *format;
951     BYTE *data, *pos;
952     BYTE byte, mask;
953     float comp_value;
954
955     if (texture == NULL || function == NULL)
956         return D3DERR_INVALIDCALL;
957
958     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
959
960     for (m = 0; m < miplevels; m++)
961     {
962         if (FAILED(IDirect3DTexture9_GetLevelDesc(texture, m, &desc)))
963             return D3DERR_INVALIDCALL;
964
965         format = get_format_info(desc.Format);
966         if (format->format == D3DFMT_UNKNOWN)
967         {
968             FIXME("Unsupported texture format %#x\n", desc.Format);
969             return D3DERR_INVALIDCALL;
970         }
971
972         if (FAILED(IDirect3DTexture9_LockRect(texture, m, &lock_rect, NULL, D3DLOCK_DISCARD)))
973             return D3DERR_INVALIDCALL;
974
975         size.x = 1.0f / desc.Width;
976         size.y = 1.0f / desc.Height;
977
978         data = lock_rect.pBits;
979
980         for (y = 0; y < desc.Height; y++)
981         {
982             /* The callback function expects the coordinates of the center
983                of the texel */
984             coord.y = (y + 0.5f) / desc.Height;
985
986             for (x = 0; x < desc.Width; x++)
987             {
988                 coord.x = (x + 0.5f) / desc.Width;
989
990                 function(&value, &coord, &size, funcdata);
991
992                 pos = data + y * lock_rect.Pitch + x * format->bytes_per_pixel;
993
994                 for (i = 0; i < format->bytes_per_pixel; i++)
995                     pos[i] = 0;
996
997                 for (c = 0; c < 4; c++)
998                 {
999                     switch (c)
1000                     {
1001                         case 0: /* Alpha */
1002                             comp_value = value.w;
1003                             break;
1004                         case 1: /* Red */
1005                             comp_value = value.x;
1006                             break;
1007                         case 2: /* Green */
1008                             comp_value = value.y;
1009                             break;
1010                         case 3: /* Blue */
1011                             comp_value = value.z;
1012                             break;
1013                     }
1014
1015                     v = comp_value * ((1 << format->bits[c]) - 1) + 0.5f;
1016
1017                     for (i = 0; i < format->bits[c] + format->shift[c]; i += 8)
1018                     {
1019                         mask = ((1 << format->bits[c]) - 1) << format->shift[c] >> i;
1020                         byte = (v << format->shift[c] >> i) & mask;
1021                         pos[i / 8] |= byte;
1022                     }
1023                 }
1024             }
1025         }
1026         IDirect3DTexture9_UnlockRect(texture, m);
1027     }
1028
1029     return D3D_OK;
1030 }
1031
1032 enum cube_coord
1033 {
1034     XCOORD = 0,
1035     XCOORDINV = 1,
1036     YCOORD = 2,
1037     YCOORDINV = 3,
1038     ZERO = 4,
1039     ONE = 5
1040 };
1041
1042 static float get_cube_coord(enum cube_coord coord, unsigned int x, unsigned int y, unsigned int size)
1043 {
1044     switch (coord)
1045     {
1046         case XCOORD:
1047             return x + 0.5f;
1048         case XCOORDINV:
1049             return size - x - 0.5f;
1050         case YCOORD:
1051             return y + 0.5f;
1052         case YCOORDINV:
1053             return size - y - 0.5f;
1054         case ZERO:
1055             return 0.0f;
1056         case ONE:
1057             return size;
1058        default:
1059            ERR("Unexpected coordinate value\n");
1060            return 0.0f;
1061     }
1062 }
1063
1064 HRESULT WINAPI D3DXFillCubeTexture(LPDIRECT3DCUBETEXTURE9 texture,
1065                                    LPD3DXFILL3D function,
1066                                    LPVOID funcdata)
1067 {
1068     DWORD miplevels;
1069     DWORD m, i, x, y, c, f, v;
1070     D3DSURFACE_DESC desc;
1071     D3DLOCKED_RECT lock_rect;
1072     D3DXVECTOR4 value;
1073     D3DXVECTOR3 coord, size;
1074     const PixelFormatDesc *format;
1075     BYTE *data, *pos;
1076     BYTE byte, mask;
1077     float comp_value;
1078     static const enum cube_coord coordmap[6][3] =
1079         {
1080             {ONE, YCOORDINV, XCOORDINV},
1081             {ZERO, YCOORDINV, XCOORD},
1082             {XCOORD, ONE, YCOORD},
1083             {XCOORD, ZERO, YCOORDINV},
1084             {XCOORD, YCOORDINV, ONE},
1085             {XCOORDINV, YCOORDINV, ZERO}
1086         };
1087
1088     if (texture == NULL || function == NULL)
1089         return D3DERR_INVALIDCALL;
1090
1091     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1092
1093     for (m = 0; m < miplevels; m++)
1094     {
1095         if (FAILED(IDirect3DCubeTexture9_GetLevelDesc(texture, m, &desc)))
1096             return D3DERR_INVALIDCALL;
1097
1098         format = get_format_info(desc.Format);
1099         if (format->format == D3DFMT_UNKNOWN)
1100         {
1101             FIXME("Unsupported texture format %#x\n", desc.Format);
1102             return D3DERR_INVALIDCALL;
1103         }
1104
1105         for (f = 0; f < 6; f++)
1106         {
1107             if (FAILED(IDirect3DCubeTexture9_LockRect(texture, f, m, &lock_rect, NULL, D3DLOCK_DISCARD)))
1108                 return D3DERR_INVALIDCALL;
1109
1110             size.x = (f == 0) || (f == 1) ? 0.0f : 2.0f / desc.Width;
1111             size.y = (f == 2) || (f == 3) ? 0.0f : 2.0f / desc.Width;
1112             size.z = (f == 4) || (f == 5) ? 0.0f : 2.0f / desc.Width;
1113
1114             data = lock_rect.pBits;
1115
1116             for (y = 0; y < desc.Height; y++)
1117             {
1118                 for (x = 0; x < desc.Width; x++)
1119                 {
1120                     coord.x = get_cube_coord(coordmap[f][0], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1121                     coord.y = get_cube_coord(coordmap[f][1], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1122                     coord.z = get_cube_coord(coordmap[f][2], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
1123
1124                     function(&value, &coord, &size, funcdata);
1125
1126                     pos = data + y * lock_rect.Pitch + x * format->bytes_per_pixel;
1127
1128                     for (i = 0; i < format->bytes_per_pixel; i++)
1129                         pos[i] = 0;
1130
1131                     for (c = 0; c < 4; c++)
1132                     {
1133                         switch (c)
1134                         {
1135                             case 0: /* Alpha */
1136                                 comp_value = value.w;
1137                                 break;
1138                             case 1: /* Red */
1139                                 comp_value = value.x;
1140                                 break;
1141                             case 2: /* Green */
1142                                 comp_value = value.y;
1143                                 break;
1144                             case 3: /* Blue */
1145                                 comp_value = value.z;
1146                                 break;
1147                         }
1148
1149                         v = comp_value * ((1 << format->bits[c]) - 1) + 0.5f;
1150
1151                         for (i = 0; i < format->bits[c] + format->shift[c]; i += 8)
1152                         {
1153                             mask = ((1 << format->bits[c]) - 1) << format->shift[c] >> i;
1154                             byte = (v << format->shift[c] >> i) & mask;
1155                             pos[i / 8] |= byte;
1156                         }
1157                     }
1158                 }
1159             }
1160             IDirect3DCubeTexture9_UnlockRect(texture, f, m);
1161         }
1162     }
1163
1164     return D3D_OK;
1165 }
1166
1167 HRESULT WINAPI D3DXFillVolumeTexture(LPDIRECT3DVOLUMETEXTURE9 texture,
1168                                      LPD3DXFILL3D function,
1169                                      LPVOID funcdata)
1170 {
1171     DWORD miplevels;
1172     DWORD m, i, x, y, z, c, v;
1173     D3DVOLUME_DESC desc;
1174     D3DLOCKED_BOX lock_box;
1175     D3DXVECTOR4 value;
1176     D3DXVECTOR3 coord, size;
1177     const PixelFormatDesc *format;
1178     BYTE *data, *pos;
1179     BYTE byte, mask;
1180     float comp_value;
1181
1182     if (texture == NULL || function == NULL)
1183         return D3DERR_INVALIDCALL;
1184
1185     miplevels = IDirect3DBaseTexture9_GetLevelCount(texture);
1186
1187     for (m = 0; m < miplevels; m++)
1188     {
1189         if (FAILED(IDirect3DVolumeTexture9_GetLevelDesc(texture, m, &desc)))
1190             return D3DERR_INVALIDCALL;
1191
1192         format = get_format_info(desc.Format);
1193         if (format->format == D3DFMT_UNKNOWN)
1194         {
1195             FIXME("Unsupported texture format %#x\n", desc.Format);
1196             return D3DERR_INVALIDCALL;
1197         }
1198
1199         if (FAILED(IDirect3DVolumeTexture9_LockBox(texture, m, &lock_box, NULL, D3DLOCK_DISCARD)))
1200             return D3DERR_INVALIDCALL;
1201
1202         size.x = 1.0f / desc.Width;
1203         size.y = 1.0f / desc.Height;
1204         size.z = 1.0f / desc.Depth;
1205
1206         data = lock_box.pBits;
1207
1208         for (z = 0; z < desc.Depth; z++)
1209         {
1210             /* The callback function expects the coordinates of the center
1211                of the texel */
1212             coord.z = (z + 0.5f) / desc.Depth;
1213
1214             for (y = 0; y < desc.Height; y++)
1215             {
1216                 coord.y = (y + 0.5f) / desc.Height;
1217
1218                 for (x = 0; x < desc.Width; x++)
1219                 {
1220                     coord.x = (x + 0.5f) / desc.Width;
1221
1222                     function(&value, &coord, &size, funcdata);
1223
1224                     pos = data + z * lock_box.SlicePitch + y * lock_box.RowPitch + x * format->bytes_per_pixel;
1225
1226                     for (i = 0; i < format->bytes_per_pixel; i++)
1227                         pos[i] = 0;
1228
1229                     for (c = 0; c < 4; c++)
1230                     {
1231                         switch (c)
1232                         {
1233                             case 0: /* Alpha */
1234                                 comp_value = value.w;
1235                                 break;
1236                             case 1: /* Red */
1237                                 comp_value = value.x;
1238                                 break;
1239                             case 2: /* Green */
1240                                 comp_value = value.y;
1241                                 break;
1242                             case 3: /* Blue */
1243                                 comp_value = value.z;
1244                                 break;
1245                         }
1246
1247                         v = comp_value * ((1 << format->bits[c]) - 1) + 0.5f;
1248
1249                         for (i = 0; i < format->bits[c] + format->shift[c]; i += 8)
1250                         {
1251                             mask = ((1 << format->bits[c]) - 1) << format->shift[c] >> i;
1252                             byte = (v << format->shift[c] >> i) & mask;
1253                             pos[i / 8] |= byte;
1254                         }
1255                     }
1256                 }
1257             }
1258         }
1259         IDirect3DVolumeTexture9_UnlockBox(texture, m);
1260     }
1261
1262     return D3D_OK;
1263 }