winmm: GetDeviceID only considers a single name per entry.
[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  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "wine/unicode.h"
22 #include "wine/debug.h"
23 #include "d3dx9_36_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
26
27 /* Returns TRUE if num is a power of 2, FALSE if not, or if 0 */
28 static BOOL is_pow2(UINT num)
29 {
30     return !(num & (num - 1));
31 }
32
33 /* Returns the smallest power of 2 which is greater than or equal to num */
34 static UINT make_pow2(UINT num)
35 {
36     UINT result = 1;
37
38     /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */
39     if (num >= 0x80000000)
40         return 0x80000000;
41
42     while (result < num)
43         result <<= 1;
44
45     return result;
46 }
47
48 HRESULT WINAPI D3DXFilterTexture(LPDIRECT3DBASETEXTURE9 texture,
49                                  CONST PALETTEENTRY *palette,
50                                  UINT srclevel,
51                                  DWORD filter)
52 {
53     UINT level = srclevel + 1;
54     HRESULT hr;
55
56     TRACE("(%p, %p, %d, %d)\n", texture, palette, srclevel, filter);
57
58     if (!texture)
59         return D3DERR_INVALIDCALL;
60
61     if ((filter & 0xFFFF) > D3DX_FILTER_BOX && filter != D3DX_DEFAULT)
62         return D3DERR_INVALIDCALL;
63
64     if (srclevel >= IDirect3DBaseTexture9_GetLevelCount(texture))
65         return D3DERR_INVALIDCALL;
66
67     switch (IDirect3DBaseTexture9_GetType(texture))
68     {
69         case D3DRTYPE_TEXTURE:
70         {
71             IDirect3DSurface9 *topsurf, *mipsurf;
72             D3DSURFACE_DESC desc;
73
74             if (filter == D3DX_DEFAULT)
75             {
76                 IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc);
77
78                 if (is_pow2(desc.Width) && is_pow2(desc.Height))
79                     filter = D3DX_FILTER_BOX;
80                 else
81                     filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER;
82             }
83
84             hr = IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) texture, srclevel, &topsurf);
85
86             if (FAILED(hr))
87                 return D3DERR_INVALIDCALL;
88
89             while (IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) texture, level, &mipsurf) == D3D_OK)
90             {
91                 hr = D3DXLoadSurfaceFromSurface(mipsurf, palette, NULL, topsurf, palette, NULL, filter, 0);
92                 IDirect3DSurface9_Release(mipsurf);
93
94                 if (FAILED(hr))
95                     break;
96
97                 level++;
98             }
99
100             IDirect3DSurface9_Release(topsurf);
101
102             if (level == srclevel + 1)
103                 return D3DERR_INVALIDCALL;
104
105             return D3D_OK;
106         }
107
108         default:
109             FIXME("Implement volume and cube texture filtering\n");
110             return E_NOTIMPL;
111     }
112 }
113
114 HRESULT WINAPI D3DXCheckTextureRequirements(LPDIRECT3DDEVICE9 device,
115                                             UINT* width,
116                                             UINT* height,
117                                             UINT* miplevels,
118                                             DWORD usage,
119                                             D3DFORMAT* format,
120                                             D3DPOOL pool)
121 {
122     UINT w = (width && *width) ? *width : 1;
123     UINT h = (height && *height) ? *height : 1;
124     D3DCAPS9 caps;
125
126     TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool);
127
128     if (!device)
129         return D3DERR_INVALIDCALL;
130
131     /* usage */
132     if ((usage != D3DX_DEFAULT) &&
133         (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES)))
134         return D3DERR_INVALIDCALL;
135
136     /* pool */
137     if ((pool != D3DPOOL_DEFAULT) && (pool != D3DPOOL_MANAGED) && (pool != D3DPOOL_SYSTEMMEM) && (pool != D3DPOOL_SCRATCH))
138         return D3DERR_INVALIDCALL;
139
140     /* width and height */
141     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
142         return D3DERR_INVALIDCALL;
143
144     /* 256 x 256 default width/height */
145     if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT))
146         w = h = 256;
147     else if (w == D3DX_DEFAULT)
148         w = (height ? h : 256);
149     else if (h == D3DX_DEFAULT)
150         h = (width ? w : 256);
151
152     /* ensure width/height is power of 2 */
153     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w)))
154         w = make_pow2(w);
155
156     if (w > caps.MaxTextureWidth)
157         w = caps.MaxTextureWidth;
158
159     if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h)))
160         h = make_pow2(h);
161
162     if (h > caps.MaxTextureHeight)
163         h = caps.MaxTextureHeight;
164
165     /* texture must be square? */
166     if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
167     {
168         if (w > h)
169             h = w;
170         else
171             w = h;
172     }
173
174     if (width)
175         *width = w;
176
177     if (height)
178         *height = h;
179
180     /* miplevels */
181     if (miplevels)
182     {
183         UINT max_mipmaps = 1;
184
185         if (!width && !height)
186             max_mipmaps = 9;    /* number of mipmaps in a 256x256 texture */
187         else
188         {
189             UINT max_dimen = max(w, h);
190
191             while (max_dimen > 1)
192             {
193                 max_dimen >>= 1;
194                 max_mipmaps++;
195             }
196         }
197
198         if (*miplevels == 0 || *miplevels > max_mipmaps)
199             *miplevels = max_mipmaps;
200     }
201
202     /* format */
203     if (format)
204     {
205         D3DDEVICE_CREATION_PARAMETERS params;
206         IDirect3D9 *d3d = NULL;
207         D3DDISPLAYMODE mode;
208         HRESULT hr;
209
210         hr = IDirect3DDevice9_GetDirect3D(device, &d3d);
211
212         if (FAILED(hr))
213             goto cleanup;
214
215         hr = IDirect3DDevice9_GetCreationParameters(device, &params);
216
217         if (FAILED(hr))
218             goto cleanup;
219
220         hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode);
221
222         if (FAILED(hr))
223             goto cleanup;
224
225         if ((*format == D3DFMT_UNKNOWN) || (*format == D3DX_DEFAULT))
226             *format = D3DFMT_A8R8G8B8;
227
228         hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format, usage,
229             D3DRTYPE_TEXTURE, *format);
230
231         if (FAILED(hr))
232             FIXME("Pixel format adjustment not implemented yet\n");
233
234 cleanup:
235
236         if (d3d)
237             IDirect3D9_Release(d3d);
238
239         if (FAILED(hr))
240             return D3DERR_INVALIDCALL;
241     }
242
243     return D3D_OK;
244 }
245
246 HRESULT WINAPI D3DXCreateTexture(LPDIRECT3DDEVICE9 pDevice,
247                                  UINT width,
248                                  UINT height,
249                                  UINT miplevels,
250                                  DWORD usage,
251                                  D3DFORMAT format,
252                                  D3DPOOL pool,
253                                  LPDIRECT3DTEXTURE9 *ppTexture)
254 {
255     HRESULT hr;
256
257     TRACE("(%p, %u, %u, %u, %x, %x, %x, %p)\n", pDevice, width, height, miplevels, usage, format,
258         pool, ppTexture);
259
260     if (!pDevice || !ppTexture)
261         return D3DERR_INVALIDCALL;
262
263     hr = D3DXCheckTextureRequirements(pDevice, &width, &height, &miplevels, usage, &format, pool);
264
265     if (FAILED(hr))
266         return hr;
267
268     return IDirect3DDevice9_CreateTexture(pDevice, width, height, miplevels, usage, format, pool, ppTexture, NULL);
269 }
270
271 HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(LPDIRECT3DDEVICE9 device,
272                                                    LPCVOID srcdata,
273                                                    UINT srcdatasize,
274                                                    UINT width,
275                                                    UINT height,
276                                                    UINT miplevels,
277                                                    DWORD usage,
278                                                    D3DFORMAT format,
279                                                    D3DPOOL pool,
280                                                    DWORD filter,
281                                                    DWORD mipfilter,
282                                                    D3DCOLOR colorkey,
283                                                    D3DXIMAGE_INFO* srcinfo,
284                                                    PALETTEENTRY* palette,
285                                                    LPDIRECT3DTEXTURE9* texture)
286 {
287     IDirect3DTexture9 **texptr;
288     IDirect3DTexture9 *buftex;
289     IDirect3DSurface9 *surface;
290     BOOL file_width = FALSE, file_height = FALSE;
291     BOOL file_format = FALSE, file_miplevels = FALSE;
292     D3DXIMAGE_INFO imginfo;
293     D3DCAPS9 caps;
294     HRESULT hr;
295
296     TRACE("(%p, %p, %u, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p)\n", device, srcdata, srcdatasize, width,
297         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
298
299     /* check for invalid parameters */
300     if (!device || !texture || !srcdata || !srcdatasize)
301         return D3DERR_INVALIDCALL;
302
303     hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo);
304
305     if (FAILED(hr))
306     {
307         *texture = NULL;
308         return hr;
309     }
310
311     /* handle default values */
312     if (width == 0 || width == D3DX_DEFAULT_NONPOW2)
313         width = imginfo.Width;
314
315     if (height == 0 || height == D3DX_DEFAULT_NONPOW2)
316         height = imginfo.Height;
317
318     if (width == D3DX_DEFAULT)
319         width = make_pow2(imginfo.Width);
320
321     if (height == D3DX_DEFAULT)
322         height = make_pow2(imginfo.Height);
323
324     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
325         format = imginfo.Format;
326
327     if (width == D3DX_FROM_FILE)
328     {
329         file_width = TRUE;
330         width = imginfo.Width;
331     }
332
333     if (height == D3DX_FROM_FILE)
334     {
335         file_height = TRUE;
336         height = imginfo.Height;
337     }
338
339     if (format == D3DFMT_FROM_FILE)
340     {
341         file_format = TRUE;
342         format = imginfo.Format;
343     }
344
345     if (miplevels == D3DX_FROM_FILE)
346     {
347         file_miplevels = TRUE;
348         miplevels = imginfo.MipLevels;
349     }
350
351     /* fix texture creation parameters */
352     hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
353
354     if (FAILED(hr))
355     {
356         *texture = NULL;
357         return hr;
358     }
359
360     if (((file_width) && (width != imginfo.Width))    ||
361         ((file_height) && (height != imginfo.Height)) ||
362         ((file_format) && (format != imginfo.Format)) ||
363         ((file_miplevels) && (miplevels != imginfo.MipLevels)))
364     {
365         return D3DERR_NOTAVAILABLE;
366     }
367
368     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
369         return D3DERR_INVALIDCALL;
370
371     /* Create the to-be-filled texture */
372     if ((caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (pool != D3DPOOL_DEFAULT) && (usage != D3DUSAGE_DYNAMIC))
373     {
374         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
375         texptr = texture;
376     }
377     else
378     {
379         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
380         texptr = &buftex;
381     }
382
383     if (FAILED(hr))
384     {
385         *texture = NULL;
386         return hr;
387     }
388
389     /* Load the file */
390     IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface);
391     hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL);
392     IDirect3DSurface9_Release(surface);
393
394     if (FAILED(hr))
395     {
396         IDirect3DTexture9_Release(*texptr);
397         *texture = NULL;
398         return hr;
399     }
400
401     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, 0, mipfilter);
402
403     if (FAILED(hr))
404     {
405         IDirect3DTexture9_Release(*texptr);
406         *texture = NULL;
407         return hr;
408     }
409
410     /* Move the data to the actual texture if necessary */
411     if (texptr == &buftex)
412     {
413         hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
414
415         if (FAILED(hr))
416         {
417             IDirect3DTexture9_Release(buftex);
418             *texture = NULL;
419             return hr;
420         }
421
422         IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)buftex, (IDirect3DBaseTexture9*)(*texture));
423         IDirect3DTexture9_Release(buftex);
424     }
425
426     if (srcinfo)
427         *srcinfo = imginfo;
428
429     return D3D_OK;
430 }
431
432 HRESULT WINAPI D3DXCreateTextureFromFileInMemory(LPDIRECT3DDEVICE9 device,
433                                                  LPCVOID srcdata,
434                                                  UINT srcdatasize,
435                                                  LPDIRECT3DTEXTURE9 *texture)
436 {
437     TRACE("(%p, %p, %d, %p)\n", device, srcdata, srcdatasize, texture);
438
439     return D3DXCreateTextureFromFileInMemoryEx(device, srcdata, srcdatasize, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
440                                                D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
441 }
442
443 HRESULT WINAPI D3DXCreateTextureFromFileExW(LPDIRECT3DDEVICE9 device,
444                                             LPCWSTR srcfile,
445                                             UINT width,
446                                             UINT height,
447                                             UINT miplevels,
448                                             DWORD usage,
449                                             D3DFORMAT format,
450                                             D3DPOOL pool,
451                                             DWORD filter,
452                                             DWORD mipfilter,
453                                             D3DCOLOR colorkey,
454                                             D3DXIMAGE_INFO *srcinfo,
455                                             PALETTEENTRY *palette,
456                                             LPDIRECT3DTEXTURE9 *texture)
457 {
458     HRESULT hr;
459     DWORD size;
460     LPVOID buffer;
461
462     TRACE("(%p, %p, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n", device, debugstr_w(srcfile), width,
463         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
464
465     if (!srcfile)
466         return D3DERR_INVALIDCALL;
467
468     hr = map_view_of_file(srcfile, &buffer, &size);
469     if (FAILED(hr))
470         return D3DXERR_INVALIDDATA;
471
472     hr = D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width, height, miplevels, usage, format, pool,
473         filter, mipfilter, colorkey, srcinfo, palette, texture);
474
475     UnmapViewOfFile(buffer);
476
477     return hr;
478 }
479
480 HRESULT WINAPI D3DXCreateTextureFromFileExA(LPDIRECT3DDEVICE9 device,
481                                             LPCSTR srcfile,
482                                             UINT width,
483                                             UINT height,
484                                             UINT miplevels,
485                                             DWORD usage,
486                                             D3DFORMAT format,
487                                             D3DPOOL pool,
488                                             DWORD filter,
489                                             DWORD mipfilter,
490                                             D3DCOLOR colorkey,
491                                             D3DXIMAGE_INFO *srcinfo,
492                                             PALETTEENTRY *palette,
493                                             LPDIRECT3DTEXTURE9 *texture)
494 {
495     LPWSTR widename;
496     HRESULT hr;
497     DWORD len;
498
499     TRACE("(%p, %p, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n", device, debugstr_a(srcfile), width,
500         height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
501
502     if (!device || !srcfile || !texture)
503         return D3DERR_INVALIDCALL;
504
505     len = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0);
506     widename = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
507     MultiByteToWideChar(CP_ACP, 0, srcfile, -1, widename, len);
508
509     hr = D3DXCreateTextureFromFileExW(device, widename, width, height, miplevels,
510                                       usage, format, pool, filter, mipfilter,
511                                       colorkey, srcinfo, palette, texture);
512
513     HeapFree(GetProcessHeap(), 0, widename);
514     return hr;
515 }
516
517 HRESULT WINAPI D3DXCreateTextureFromFileA(LPDIRECT3DDEVICE9 device,
518                                           LPCSTR srcfile,
519                                           LPDIRECT3DTEXTURE9 *texture)
520 {
521     TRACE("(%p, %s, %p)\n", device, debugstr_a(srcfile), texture);
522
523     return D3DXCreateTextureFromFileExA(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
524                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
525 }
526
527 HRESULT WINAPI D3DXCreateTextureFromFileW(LPDIRECT3DDEVICE9 device,
528                                           LPCWSTR srcfile,
529                                           LPDIRECT3DTEXTURE9 *texture)
530 {
531     TRACE("(%p, %s, %p)\n", device, debugstr_w(srcfile), texture);
532
533     return D3DXCreateTextureFromFileExW(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
534                                         D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture);
535 }