X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=dll%2Fdirectx%2Fwine%2Fd3dx9_36%2Ftexture.c;h=d33b4634a52c5e84a545cf87f59d4424ecce0020;hp=f47853a89dfa3eb7e5034f8201ce1a704b31d4a6;hb=e7054d7688e14c4a85f72cac70959a101d5f976c;hpb=18ac12569f32eb04c6e96545f67cc583b1c6bcaf diff --git a/dll/directx/wine/d3dx9_36/texture.c b/dll/directx/wine/d3dx9_36/texture.c index f47853a89df..d33b4634a52 100644 --- a/dll/directx/wine/d3dx9_36/texture.c +++ b/dll/directx/wine/d3dx9_36/texture.c @@ -1,5 +1,8 @@ /* + * Copyright 2009 Tony Wasserka * Copyright 2010 Christian Costa + * Copyright 2010 Owen Rudge for CodeWeavers + * Copyright 2010 Matteo Bruni for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,22 +19,1895 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wine/debug.h" #include "d3dx9_36_private.h" -WINE_DEFAULT_DEBUG_CHANNEL(d3dx); +/* Returns TRUE if num is a power of 2, FALSE if not, or if 0 */ +static BOOL is_pow2(UINT num) +{ + return !(num & (num - 1)); +} + +/* Returns the smallest power of 2 which is greater than or equal to num */ +static UINT make_pow2(UINT num) +{ + UINT result = 1; + + /* In the unlikely event somebody passes a large value, make sure we don't enter an infinite loop */ + if (num >= 0x80000000) + return 0x80000000; + + while (result < num) + result <<= 1; + + return result; +} + +static HRESULT get_surface(D3DRESOURCETYPE type, struct IDirect3DBaseTexture9 *tex, + int face, UINT level, struct IDirect3DSurface9 **surf) +{ + switch (type) + { + case D3DRTYPE_TEXTURE: + return IDirect3DTexture9_GetSurfaceLevel((IDirect3DTexture9*) tex, level, surf); + case D3DRTYPE_CUBETEXTURE: + return IDirect3DCubeTexture9_GetCubeMapSurface((IDirect3DCubeTexture9*) tex, face, level, surf); + default: + ERR("Unexpected texture type\n"); + return E_NOTIMPL; + } +} + +HRESULT WINAPI D3DXFilterTexture(IDirect3DBaseTexture9 *texture, + const PALETTEENTRY *palette, + UINT srclevel, + DWORD filter) +{ + UINT level; + HRESULT hr; + D3DRESOURCETYPE type; + + TRACE("(%p, %p, %u, %#x)\n", texture, palette, srclevel, filter); + + if (!texture) + return D3DERR_INVALIDCALL; + + if ((filter & 0xFFFF) > D3DX_FILTER_BOX && filter != D3DX_DEFAULT) + return D3DERR_INVALIDCALL; + + if (srclevel == D3DX_DEFAULT) + srclevel = 0; + else if (srclevel >= IDirect3DBaseTexture9_GetLevelCount(texture)) + return D3DERR_INVALIDCALL; + + switch (type = IDirect3DBaseTexture9_GetType(texture)) + { + case D3DRTYPE_TEXTURE: + case D3DRTYPE_CUBETEXTURE: + { + IDirect3DSurface9 *topsurf, *mipsurf; + D3DSURFACE_DESC desc; + int i, numfaces; + + if (type == D3DRTYPE_TEXTURE) + { + numfaces = 1; + IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc); + } + else + { + numfaces = 6; + IDirect3DCubeTexture9_GetLevelDesc((IDirect3DTexture9*) texture, srclevel, &desc); + } + + if (filter == D3DX_DEFAULT) + { + if (is_pow2(desc.Width) && is_pow2(desc.Height)) + filter = D3DX_FILTER_BOX; + else + filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER; + } + + for (i = 0; i < numfaces; i++) + { + level = srclevel + 1; + hr = get_surface(type, texture, i, srclevel, &topsurf); + + if (FAILED(hr)) + return D3DERR_INVALIDCALL; + + while (get_surface(type, texture, i, level, &mipsurf) == D3D_OK) + { + hr = D3DXLoadSurfaceFromSurface(mipsurf, palette, NULL, topsurf, palette, NULL, filter, 0); + IDirect3DSurface9_Release(topsurf); + topsurf = mipsurf; + + if (FAILED(hr)) + break; + + level++; + } + + IDirect3DSurface9_Release(topsurf); + if (FAILED(hr)) + return hr; + } + + return D3D_OK; + } + + case D3DRTYPE_VOLUMETEXTURE: + { + D3DVOLUME_DESC desc; + int level, level_count; + IDirect3DVolume9 *top_volume, *mip_volume; + IDirect3DVolumeTexture9 *volume_texture = (IDirect3DVolumeTexture9*) texture; + + IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, srclevel, &desc); + + if (filter == D3DX_DEFAULT) + { + if (is_pow2(desc.Width) && is_pow2(desc.Height) && is_pow2(desc.Depth)) + filter = D3DX_FILTER_BOX; + else + filter = D3DX_FILTER_BOX | D3DX_FILTER_DITHER; + } + + hr = IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, srclevel, &top_volume); + if (FAILED(hr)) + return hr; + + level_count = IDirect3DVolumeTexture9_GetLevelCount(volume_texture); + for (level = srclevel + 1; level < level_count; level++) + { + IDirect3DVolumeTexture9_GetVolumeLevel(volume_texture, level, &mip_volume); + hr = D3DXLoadVolumeFromVolume(mip_volume, palette, NULL, top_volume, palette, NULL, filter, 0); + IDirect3DVolume9_Release(top_volume); + top_volume = mip_volume; + + if (FAILED(hr)) + break; + } + + IDirect3DVolume9_Release(top_volume); + if (FAILED(hr)) + return hr; + + return D3D_OK; + } + + default: + return D3DERR_INVALIDCALL; + } +} + +static D3DFORMAT get_luminance_replacement_format(D3DFORMAT format) +{ + static const struct + { + D3DFORMAT luminance_format; + D3DFORMAT replacement_format; + } luminance_replacements[] = + { + {D3DFMT_L8, D3DFMT_X8R8G8B8}, + {D3DFMT_A8L8, D3DFMT_A8R8G8B8}, + {D3DFMT_A4L4, D3DFMT_A4R4G4B4}, + {D3DFMT_L16, D3DFMT_A16B16G16R16} + }; + unsigned int i; + + for (i = 0; i < sizeof(luminance_replacements) / sizeof(luminance_replacements[0]); ++i) + if (format == luminance_replacements[i].luminance_format) + return luminance_replacements[i].replacement_format; + return format; +} + +HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height, + UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool) +{ + UINT w = (width && *width) ? *width : 1; + UINT h = (height && *height) ? *height : 1; + D3DCAPS9 caps; + D3DDEVICE_CREATION_PARAMETERS params; + IDirect3D9 *d3d = NULL; + D3DDISPLAYMODE mode; + HRESULT hr; + D3DFORMAT usedformat = D3DFMT_UNKNOWN; + const struct pixel_format_desc *fmt; + + TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool); + + if (!device) + return D3DERR_INVALIDCALL; + + /* usage */ + if (usage == D3DX_DEFAULT) + usage = 0; + if (usage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_POINTS | D3DUSAGE_RTPATCHES | D3DUSAGE_NPATCHES)) + return D3DERR_INVALIDCALL; + + /* pool */ + if ((pool != D3DPOOL_DEFAULT) && (pool != D3DPOOL_MANAGED) && (pool != D3DPOOL_SYSTEMMEM) && (pool != D3DPOOL_SCRATCH)) + return D3DERR_INVALIDCALL; + + /* format */ + if (format) + { + TRACE("Requested format %x\n", *format); + usedformat = *format; + } + + hr = IDirect3DDevice9_GetDirect3D(device, &d3d); + + if (FAILED(hr)) + goto cleanup; + + hr = IDirect3DDevice9_GetCreationParameters(device, ¶ms); + + if (FAILED(hr)) + goto cleanup; + + hr = IDirect3DDevice9_GetDisplayMode(device, 0, &mode); + + if (FAILED(hr)) + goto cleanup; + + if ((usedformat == D3DFMT_UNKNOWN) || (usedformat == D3DX_DEFAULT)) + usedformat = D3DFMT_A8R8G8B8; + + fmt = get_format_info(usedformat); + + hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format, + usage, D3DRTYPE_TEXTURE, usedformat); + if (FAILED(hr)) + { + BOOL allow_24bits; + int bestscore = INT_MIN, i = 0, j; + unsigned int channels; + const struct pixel_format_desc *curfmt, *bestfmt = NULL; + + TRACE("Requested format is not supported, looking for a fallback.\n"); + + if (!fmt) + { + FIXME("Pixel format %x not handled\n", usedformat); + goto cleanup; + } + fmt = get_format_info(get_luminance_replacement_format(usedformat)); + + allow_24bits = fmt->bytes_per_pixel == 3; + channels = !!fmt->bits[0] + !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3]; + usedformat = D3DFMT_UNKNOWN; + + while ((curfmt = get_format_info_idx(i))) + { + unsigned int curchannels = !!curfmt->bits[0] + !!curfmt->bits[1] + + !!curfmt->bits[2] + !!curfmt->bits[3]; + int score; + + i++; + + if (curchannels < channels) + continue; + if (curfmt->bytes_per_pixel == 3 && !allow_24bits) + continue; + + hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, + mode.Format, usage, D3DRTYPE_TEXTURE, curfmt->format); + if (FAILED(hr)) + continue; + + /* This format can be used, let's evaluate it. + Weights chosen quite arbitrarily... */ + score = 512 * (curfmt->type == fmt->type); + score -= 32 * (curchannels - channels); + + for (j = 0; j < 4; j++) + { + int diff = curfmt->bits[j] - fmt->bits[j]; + score -= (diff < 0 ? -diff * 8 : diff) * (j == 0 ? 1 : 2); + } + + if (score > bestscore) + { + bestscore = score; + usedformat = curfmt->format; + bestfmt = curfmt; + } + } + fmt = bestfmt; + hr = D3D_OK; + } + + if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps))) + return D3DERR_INVALIDCALL; + + if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT)) + w = h = 256; + else if (w == D3DX_DEFAULT) + w = (height ? h : 256); + else if (h == D3DX_DEFAULT) + h = (width ? w : 256); + + if (fmt->block_width != 1 || fmt->block_height != 1) + { + if (w % fmt->block_width) + w += fmt->block_width - w % fmt->block_width; + if (h % fmt->block_height) + h += fmt->block_height - h % fmt->block_height; + } + + if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w))) + w = make_pow2(w); + + if (w > caps.MaxTextureWidth) + w = caps.MaxTextureWidth; + + if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h))) + h = make_pow2(h); + + if (h > caps.MaxTextureHeight) + h = caps.MaxTextureHeight; + + if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) + { + if (w > h) + h = w; + else + w = h; + } + + if (width) + *width = w; + + if (height) + *height = h; + + if (miplevels && (usage & D3DUSAGE_AUTOGENMIPMAP)) + { + if (*miplevels > 1) + *miplevels = 0; + } + else if (miplevels) + { + UINT max_mipmaps = 1; + + if (!width && !height) + max_mipmaps = 9; /* number of mipmaps in a 256x256 texture */ + else + { + UINT max_dimen = max(w, h); + + while (max_dimen > 1) + { + max_dimen >>= 1; + max_mipmaps++; + } + } + + if (*miplevels == 0 || *miplevels > max_mipmaps) + *miplevels = max_mipmaps; + } + +cleanup: + + if (d3d) + IDirect3D9_Release(d3d); + + if (FAILED(hr)) + return hr; + + if (usedformat == D3DFMT_UNKNOWN) + { + WARN("Couldn't find a suitable pixel format\n"); + return D3DERR_NOTAVAILABLE; + } + + TRACE("Format chosen: %x\n", usedformat); + if (format) + *format = usedformat; + + return D3D_OK; +} + +HRESULT WINAPI D3DXCheckCubeTextureRequirements(struct IDirect3DDevice9 *device, UINT *size, + UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool) +{ + D3DCAPS9 caps; + UINT s = (size && *size) ? *size : 256; + HRESULT hr; + + TRACE("(%p, %p, %p, %u, %p, %u)\n", device, size, miplevels, usage, format, pool); + + if (s == D3DX_DEFAULT) + s = 256; + + if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps))) + return D3DERR_INVALIDCALL; + + if (!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP)) + return D3DERR_NOTAVAILABLE; + + /* ensure width/height is power of 2 */ + if ((caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && (!is_pow2(s))) + s = make_pow2(s); + + hr = D3DXCheckTextureRequirements(device, &s, &s, miplevels, usage, format, pool); + + if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP)) + { + if(miplevels) + *miplevels = 1; + } + + if (size) + *size = s; + + return hr; +} + +HRESULT WINAPI D3DXCheckVolumeTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height, + UINT *depth, UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool) +{ + D3DCAPS9 caps; + UINT w = width ? *width : D3DX_DEFAULT; + UINT h = height ? *height : D3DX_DEFAULT; + UINT d = (depth && *depth) ? *depth : 1; + HRESULT hr; + + TRACE("(%p, %p, %p, %p, %p, %u, %p, %u)\n", device, width, height, depth, miplevels, + usage, format, pool); + + if (!device || FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps))) + return D3DERR_INVALIDCALL; + + if (!(caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP)) + return D3DERR_NOTAVAILABLE; + + hr = D3DXCheckTextureRequirements(device, &w, &h, NULL, usage, format, pool); + if (d == D3DX_DEFAULT) + d = 1; + + /* ensure width/height is power of 2 */ + if ((caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) && + (!is_pow2(w) || !is_pow2(h) || !is_pow2(d))) + { + w = make_pow2(w); + h = make_pow2(h); + d = make_pow2(d); + } + + if (w > caps.MaxVolumeExtent) + w = caps.MaxVolumeExtent; + if (h > caps.MaxVolumeExtent) + h = caps.MaxVolumeExtent; + if (d > caps.MaxVolumeExtent) + d = caps.MaxVolumeExtent; + + if (miplevels) + { + if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP)) + *miplevels = 1; + else if ((usage & D3DUSAGE_AUTOGENMIPMAP)) + { + if (*miplevels > 1) + *miplevels = 0; + } + else + { + UINT max_mipmaps = 1; + UINT max_dimen = max(max(w, h), d); + + while (max_dimen > 1) + { + max_dimen >>= 1; + max_mipmaps++; + } -HRESULT WINAPI D3DXCreateTexture(LPDIRECT3DDEVICE9 pDevice, - UINT width, - UINT height, - UINT miplevels, - DWORD usage, - D3DFORMAT format, - D3DPOOL pool, - LPDIRECT3DTEXTURE9 *ppTexture) + if (*miplevels == 0 || *miplevels > max_mipmaps) + *miplevels = max_mipmaps; + } + } + + if (width) + *width = w; + if (height) + *height = h; + if (depth) + *depth = d; + + return hr; +} + +HRESULT WINAPI D3DXCreateTexture(struct IDirect3DDevice9 *device, UINT width, UINT height, + UINT miplevels, DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DTexture9 **texture) +{ + HRESULT hr; + + TRACE("device %p, width %u, height %u, miplevels %u, usage %#x, format %#x, pool %#x, texture %p.\n", + device, width, height, miplevels, usage, format, pool, texture); + + if (!device || !texture) + return D3DERR_INVALIDCALL; + + if (FAILED(hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool))) + return hr; + + return IDirect3DDevice9_CreateTexture(device, width, height, miplevels, usage, format, pool, texture, NULL); +} + +static D3DFORMAT get_alpha_replacement_format(D3DFORMAT format) +{ + static const struct + { + D3DFORMAT orig_format; + D3DFORMAT replacement_format; + } + replacement_formats[] = + { + {D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8}, + {D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5}, + {D3DFMT_X4R4G4B4, D3DFMT_A4R4G4B4}, + {D3DFMT_X8B8G8R8, D3DFMT_A8B8G8R8}, + {D3DFMT_L8, D3DFMT_A8L8}, + }; + unsigned int i; + + for (i = 0; i < sizeof(replacement_formats) / sizeof(replacement_formats[0]); ++i) + if (replacement_formats[i].orig_format == format) + return replacement_formats[i].replacement_format; + return format; +} + +HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *device, const void *srcdata, + UINT srcdatasize, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format, + D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo, + PALETTEENTRY *palette, struct IDirect3DTexture9 **texture) +{ + IDirect3DTexture9 **texptr; + IDirect3DTexture9 *buftex; + IDirect3DSurface9 *surface; + BOOL dynamic_texture, format_specified = FALSE; + D3DXIMAGE_INFO imginfo; + UINT loaded_miplevels, skip_levels; + D3DCAPS9 caps; + HRESULT hr; + + TRACE("device %p, srcdata %p, srcdatasize %u, width %u, height %u, miplevels %u," + " usage %#x, format %#x, pool %#x, filter %#x, mipfilter %#x, colorkey %#x," + " srcinfo %p, palette %p, texture %p.\n", + device, srcdata, srcdatasize, width, height, miplevels, usage, format, pool, + filter, mipfilter, colorkey, srcinfo, palette, texture); + + /* check for invalid parameters */ + if (!device || !texture || !srcdata || !srcdatasize) + return D3DERR_INVALIDCALL; + + hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo); + if (FAILED(hr)) + { + FIXME("Unrecognized file format, returning failure.\n"); + *texture = NULL; + return hr; + } + + /* handle default values */ + if (width == 0 || width == D3DX_DEFAULT_NONPOW2) + width = imginfo.Width; + + if (height == 0 || height == D3DX_DEFAULT_NONPOW2) + height = imginfo.Height; + + if (width == D3DX_DEFAULT) + width = make_pow2(imginfo.Width); + + if (height == D3DX_DEFAULT) + height = make_pow2(imginfo.Height); + + if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT) + format = imginfo.Format; + else + format_specified = TRUE; + + if (width == D3DX_FROM_FILE) + { + width = imginfo.Width; + } + + if (height == D3DX_FROM_FILE) + { + height = imginfo.Height; + } + + if (format == D3DFMT_FROM_FILE) + { + format = imginfo.Format; + } + + if (miplevels == D3DX_FROM_FILE) + { + miplevels = imginfo.MipLevels; + } + + skip_levels = mipfilter != D3DX_DEFAULT ? mipfilter >> D3DX_SKIP_DDS_MIP_LEVELS_SHIFT : 0; + if (skip_levels && imginfo.MipLevels > skip_levels) + { + TRACE("Skipping the first %u (of %u) levels of a DDS mipmapped texture.\n", + skip_levels, imginfo.MipLevels); + TRACE("Texture level 0 dimensions are %ux%u.\n", imginfo.Width, imginfo.Height); + width >>= skip_levels; + height >>= skip_levels; + miplevels -= skip_levels; + } + else + { + skip_levels = 0; + } + + /* fix texture creation parameters */ + hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool); + if (FAILED(hr)) + { + FIXME("Couldn't find suitable texture parameters.\n"); + *texture = NULL; + return hr; + } + + if (colorkey && !format_specified) + format = get_alpha_replacement_format(format); + + if (imginfo.MipLevels < miplevels && (D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5)) + { + FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n"); + miplevels = imginfo.MipLevels; + } + if (imginfo.ResourceType == D3DRTYPE_VOLUMETEXTURE + && D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5 && miplevels > 1) + { + FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n"); + miplevels = 1; + } + + if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps))) + return D3DERR_INVALIDCALL; + + /* Create the to-be-filled texture */ + dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC); + if (pool == D3DPOOL_DEFAULT && !dynamic_texture) + { + hr = D3DXCreateTexture(device, width, height, miplevels, 0, format, D3DPOOL_SYSTEMMEM, &buftex); + texptr = &buftex; + } + else + { + hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture); + texptr = texture; + } + + if (FAILED(hr)) + { + FIXME("Texture creation failed.\n"); + *texture = NULL; + return hr; + } + + TRACE("Texture created correctly. Now loading the texture data into it.\n"); + if (imginfo.ImageFileFormat != D3DXIFF_DDS) + { + IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface); + hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL); + IDirect3DSurface9_Release(surface); + loaded_miplevels = min(IDirect3DTexture9_GetLevelCount(*texptr), imginfo.MipLevels); + } + else + { + hr = load_texture_from_dds(*texptr, srcdata, palette, filter, colorkey, &imginfo, skip_levels, + &loaded_miplevels); + } + + if (FAILED(hr)) + { + FIXME("Texture loading failed.\n"); + IDirect3DTexture9_Release(*texptr); + *texture = NULL; + return hr; + } + + hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, loaded_miplevels - 1, mipfilter); + if (FAILED(hr)) + { + FIXME("Texture filtering failed.\n"); + IDirect3DTexture9_Release(*texptr); + *texture = NULL; + return hr; + } + + /* Move the data to the actual texture if necessary */ + if (texptr == &buftex) + { + hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture); + + if (FAILED(hr)) + { + IDirect3DTexture9_Release(buftex); + *texture = NULL; + return hr; + } + + IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)buftex, (IDirect3DBaseTexture9*)(*texture)); + IDirect3DTexture9_Release(buftex); + } + + if (srcinfo) + *srcinfo = imginfo; + + return D3D_OK; +} + +HRESULT WINAPI D3DXCreateTextureFromFileInMemory(struct IDirect3DDevice9 *device, + const void *srcdata, UINT srcdatasize, struct IDirect3DTexture9 **texture) +{ + TRACE("(%p, %p, %d, %p)\n", device, srcdata, srcdatasize, texture); + + return D3DXCreateTextureFromFileInMemoryEx(device, srcdata, srcdatasize, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture); +} + +HRESULT WINAPI D3DXCreateTextureFromFileExW(struct IDirect3DDevice9 *device, const WCHAR *srcfile, + UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format, + D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo, + PALETTEENTRY *palette, struct IDirect3DTexture9 **texture) +{ + void *buffer; + HRESULT hr; + DWORD size; + + TRACE("device %p, srcfile %s, width %u, height %u, miplevels %u, usage %#x, format %#x, " + "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n", + device, debugstr_w(srcfile), width, height, miplevels, usage, format, + pool, filter, mipfilter, colorkey, srcinfo, palette, texture); + + if (!srcfile) + return D3DERR_INVALIDCALL; + + hr = map_view_of_file(srcfile, &buffer, &size); + if (FAILED(hr)) + return D3DXERR_INVALIDDATA; + + hr = D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width, height, miplevels, usage, format, pool, + filter, mipfilter, colorkey, srcinfo, palette, texture); + + UnmapViewOfFile(buffer); + + return hr; +} + +HRESULT WINAPI D3DXCreateTextureFromFileExA(struct IDirect3DDevice9 *device, const char *srcfile, + UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format, + D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo, + PALETTEENTRY *palette, struct IDirect3DTexture9 **texture) +{ + WCHAR *widename; + HRESULT hr; + DWORD len; + + TRACE("device %p, srcfile %s, width %u, height %u, miplevels %u, usage %#x, format %#x, " + "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n", + device, debugstr_a(srcfile), width, height, miplevels, usage, format, + pool, filter, mipfilter, colorkey, srcinfo, palette, texture); + + if (!device || !srcfile || !texture) + return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0); + widename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*widename)); + MultiByteToWideChar(CP_ACP, 0, srcfile, -1, widename, len); + + hr = D3DXCreateTextureFromFileExW(device, widename, width, height, miplevels, + usage, format, pool, filter, mipfilter, + colorkey, srcinfo, palette, texture); + + HeapFree(GetProcessHeap(), 0, widename); + return hr; +} + +HRESULT WINAPI D3DXCreateTextureFromFileA(struct IDirect3DDevice9 *device, + const char *srcfile, struct IDirect3DTexture9 **texture) +{ + TRACE("(%p, %s, %p)\n", device, debugstr_a(srcfile), texture); + + return D3DXCreateTextureFromFileExA(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture); +} + +HRESULT WINAPI D3DXCreateTextureFromFileW(struct IDirect3DDevice9 *device, + const WCHAR *srcfile, struct IDirect3DTexture9 **texture) +{ + TRACE("(%p, %s, %p)\n", device, debugstr_w(srcfile), texture); + + return D3DXCreateTextureFromFileExW(device, srcfile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture); +} + + +HRESULT WINAPI D3DXCreateTextureFromResourceA(struct IDirect3DDevice9 *device, + HMODULE srcmodule, const char *resource, struct IDirect3DTexture9 **texture) +{ + TRACE("(%p, %s): relay\n", srcmodule, debugstr_a(resource)); + + return D3DXCreateTextureFromResourceExA(device, srcmodule, resource, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture); +} + +HRESULT WINAPI D3DXCreateTextureFromResourceW(struct IDirect3DDevice9 *device, + HMODULE srcmodule, const WCHAR *resource, struct IDirect3DTexture9 **texture) +{ + TRACE("(%p, %s): relay\n", srcmodule, debugstr_w(resource)); + + return D3DXCreateTextureFromResourceExW(device, srcmodule, resource, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture); +} + +HRESULT WINAPI D3DXCreateTextureFromResourceExA(struct IDirect3DDevice9 *device, HMODULE srcmodule, + const char *resource, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format, + D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo, + PALETTEENTRY *palette, struct IDirect3DTexture9 **texture) { - FIXME("(%p, %d, %d, %d, %x, %x, %x, %p): semi-stub\n", pDevice, width, height, miplevels, usage, format, - pool, ppTexture); + HRSRC resinfo; + void *buffer; + DWORD size; + + TRACE("device %p, srcmodule %p, resource %s, width %u, height %u, miplevels %u, usage %#x, format %#x, " + "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n", + device, srcmodule, debugstr_a(resource), width, height, miplevels, usage, format, + pool, filter, mipfilter, colorkey, srcinfo, palette, texture); + + if (!device || !texture) + return D3DERR_INVALIDCALL; + + if (!(resinfo = FindResourceA(srcmodule, resource, (const char *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceA(srcmodule, resource, (const char *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; + + if (FAILED(load_resource_into_memory(srcmodule, resinfo, &buffer, &size))) + return D3DXERR_INVALIDDATA; + + return D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width, height, miplevels, + usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture); +} + +HRESULT WINAPI D3DXCreateTextureFromResourceExW(struct IDirect3DDevice9 *device, HMODULE srcmodule, + const WCHAR *resource, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format, + D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo, + PALETTEENTRY *palette, struct IDirect3DTexture9 **texture) +{ + HRSRC resinfo; + void *buffer; + DWORD size; + + TRACE("device %p, srcmodule %p, resource %s, width %u, height %u, miplevels %u, usage %#x, format %#x, " + "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n", + device, srcmodule, debugstr_w(resource), width, height, miplevels, usage, format, + pool, filter, mipfilter, colorkey, srcinfo, palette, texture); + + if (!device || !texture) + return D3DERR_INVALIDCALL; + + if (!(resinfo = FindResourceW(srcmodule, resource, (const WCHAR *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceW(srcmodule, resource, (const WCHAR *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; + + if (FAILED(load_resource_into_memory(srcmodule, resinfo, &buffer, &size))) + return D3DXERR_INVALIDDATA; + + return D3DXCreateTextureFromFileInMemoryEx(device, buffer, size, width, height, miplevels, + usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture); +} + +HRESULT WINAPI D3DXCreateCubeTexture(struct IDirect3DDevice9 *device, UINT size, UINT miplevels, + DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DCubeTexture9 **texture) +{ + HRESULT hr; + + TRACE("(%p, %u, %u, %#x, %#x, %#x, %p)\n", device, size, miplevels, usage, format, + pool, texture); + + if (!device || !texture) + return D3DERR_INVALIDCALL; + + hr = D3DXCheckCubeTextureRequirements(device, &size, &miplevels, usage, &format, pool); + + if (FAILED(hr)) + { + TRACE("D3DXCheckCubeTextureRequirements failed\n"); + return hr; + } + + return IDirect3DDevice9_CreateCubeTexture(device, size, miplevels, usage, format, pool, texture, NULL); +} + +HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemory(struct IDirect3DDevice9 *device, + const void *data, UINT datasize, struct IDirect3DCubeTexture9 **texture) +{ + TRACE("(%p, %p, %u, %p)\n", device, data, datasize, texture); + + return D3DXCreateCubeTextureFromFileInMemoryEx(device, data, datasize, D3DX_DEFAULT, D3DX_DEFAULT, + 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, texture); +} + +HRESULT WINAPI D3DXCreateVolumeTexture(struct IDirect3DDevice9 *device, UINT width, UINT height, UINT depth, + UINT miplevels, DWORD usage, D3DFORMAT format, D3DPOOL pool, struct IDirect3DVolumeTexture9 **texture) +{ + HRESULT hr; + + TRACE("(%p, %u, %u, %u, %u, %#x, %#x, %#x, %p)\n", device, width, height, depth, + miplevels, usage, format, pool, texture); + + if (!device || !texture) + return D3DERR_INVALIDCALL; + + hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, + &miplevels, usage, &format, pool); + + if (FAILED(hr)) + { + TRACE("D3DXCheckVolumeTextureRequirements failed\n"); + return hr; + } + + return IDirect3DDevice9_CreateVolumeTexture(device, width, height, depth, miplevels, + usage, format, pool, texture, NULL); +} + +HRESULT WINAPI D3DXCreateVolumeTextureFromFileA(IDirect3DDevice9 *device, + const char *filename, + IDirect3DVolumeTexture9 **volume_texture) +{ + int len; + HRESULT hr; + void *data; + DWORD data_size; + WCHAR *filenameW; + + TRACE("(%p, %s, %p): relay\n", + device, debugstr_a(filename), volume_texture); + + if (!filename) return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0); + filenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!filenameW) return E_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, len); + + hr = map_view_of_file(filenameW, &data, &data_size); + HeapFree(GetProcessHeap(), 0, filenameW); + if (FAILED(hr)) return D3DXERR_INVALIDDATA; + + hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, + D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, volume_texture); + + UnmapViewOfFile(data); + return hr; +} + +HRESULT WINAPI D3DXCreateVolumeTextureFromFileW(IDirect3DDevice9 *device, + const WCHAR *filename, + IDirect3DVolumeTexture9 **volume_texture) +{ + HRESULT hr; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %p): relay\n", + device, debugstr_w(filename), volume_texture); + + if (!filename) return D3DERR_INVALIDCALL; + + hr = map_view_of_file(filename, &data, &data_size); + if (FAILED(hr)) return D3DXERR_INVALIDDATA; + + hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, + D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, volume_texture); + + UnmapViewOfFile(data); + return hr; +} + +HRESULT WINAPI D3DXCreateVolumeTextureFromFileExA(IDirect3DDevice9 *device, + const char *filename, + UINT width, + UINT height, + UINT depth, + UINT mip_levels, + DWORD usage, + D3DFORMAT format, + D3DPOOL pool, + DWORD filter, + DWORD mip_filter, + D3DCOLOR color_key, + D3DXIMAGE_INFO *src_info, + PALETTEENTRY *palette, + IDirect3DVolumeTexture9 **volume_texture) +{ + int len; + HRESULT hr; + WCHAR *filenameW; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %u, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n", + device, debugstr_a(filename), width, height, depth, mip_levels, + usage, format, pool, filter, mip_filter, color_key, src_info, + palette, volume_texture); + + if (!filename) return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0); + filenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!filenameW) return E_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, len); + + hr = map_view_of_file(filenameW, &data, &data_size); + HeapFree(GetProcessHeap(), 0, filenameW); + if (FAILED(hr)) return D3DXERR_INVALIDDATA; + + hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, width, height, depth, + mip_levels, usage, format, pool, filter, mip_filter, color_key, src_info, palette, + volume_texture); + + UnmapViewOfFile(data); + return hr; +} + +HRESULT WINAPI D3DXCreateVolumeTextureFromFileExW(IDirect3DDevice9 *device, + const WCHAR *filename, + UINT width, + UINT height, + UINT depth, + UINT mip_levels, + DWORD usage, + D3DFORMAT format, + D3DPOOL pool, + DWORD filter, + DWORD mip_filter, + D3DCOLOR color_key, + D3DXIMAGE_INFO *src_info, + PALETTEENTRY *palette, + IDirect3DVolumeTexture9 **volume_texture) +{ + HRESULT hr; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %u, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n", + device, debugstr_w(filename), width, height, depth, mip_levels, + usage, format, pool, filter, mip_filter, color_key, src_info, + palette, volume_texture); + + if (!filename) return D3DERR_INVALIDCALL; + + hr = map_view_of_file(filename, &data, &data_size); + if (FAILED(hr)) return D3DXERR_INVALIDDATA; + + hr = D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, width, height, depth, + mip_levels, usage, format, pool, filter, mip_filter, color_key, src_info, palette, + volume_texture); + + UnmapViewOfFile(data); + return hr; +} + +HRESULT WINAPI D3DXCreateVolumeTextureFromFileInMemory(IDirect3DDevice9 *device, + const void *data, + UINT data_size, + IDirect3DVolumeTexture9 **volume_texture) +{ + TRACE("(%p, %p, %u, %p): relay\n", device, data, data_size, volume_texture); + + return D3DXCreateVolumeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, + D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, + 0, NULL, NULL, volume_texture); +} + +HRESULT WINAPI D3DXCreateVolumeTextureFromFileInMemoryEx(IDirect3DDevice9 *device, + const void *data, + UINT data_size, + UINT width, + UINT height, + UINT depth, + UINT mip_levels, + DWORD usage, + D3DFORMAT format, + D3DPOOL pool, + DWORD filter, + DWORD mip_filter, + D3DCOLOR color_key, + D3DXIMAGE_INFO *info, + PALETTEENTRY *palette, + IDirect3DVolumeTexture9 **volume_texture) +{ + HRESULT hr; + D3DCAPS9 caps; + D3DXIMAGE_INFO image_info; + BOOL dynamic_texture; + BOOL file_width = FALSE; + BOOL file_height = FALSE; + BOOL file_depth = FALSE; + BOOL file_format = FALSE; + BOOL file_mip_levels = FALSE; + IDirect3DVolumeTexture9 *tex, *buftex; + + TRACE("(%p, %p, %u, %u, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p)\n", + device, data, data_size, width, height, depth, mip_levels, usage, format, pool, + filter, mip_filter, color_key, info, palette, volume_texture); + + if (!device || !data || !data_size || !volume_texture) + return D3DERR_INVALIDCALL; + + hr = D3DXGetImageInfoFromFileInMemory(data, data_size, &image_info); + if (FAILED(hr)) return hr; + + if (image_info.ImageFileFormat != D3DXIFF_DDS) + return D3DXERR_INVALIDDATA; + + if (width == 0 || width == D3DX_DEFAULT_NONPOW2) + width = image_info.Width; + if (width == D3DX_DEFAULT) + width = make_pow2(image_info.Width); + + if (height == 0 || height == D3DX_DEFAULT_NONPOW2) + height = image_info.Height; + if (height == D3DX_DEFAULT) + height = make_pow2(image_info.Height); + + if (depth == 0 || depth == D3DX_DEFAULT_NONPOW2) + depth = image_info.Depth; + if (depth == D3DX_DEFAULT) + depth = make_pow2(image_info.Depth); + + if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT) + format = image_info.Format; + + if (width == D3DX_FROM_FILE) + { + file_width = TRUE; + width = image_info.Width; + } + + if (height == D3DX_FROM_FILE) + { + file_height = TRUE; + height = image_info.Height; + } + + if (depth == D3DX_FROM_FILE) + { + file_depth = TRUE; + depth = image_info.Depth; + } + + if (format == D3DFMT_FROM_FILE) + { + file_format = TRUE; + format = image_info.Format; + } + + if (mip_levels == D3DX_FROM_FILE) + { + file_mip_levels = TRUE; + mip_levels = image_info.MipLevels; + } + + hr = D3DXCheckVolumeTextureRequirements(device, &width, &height, &depth, &mip_levels, usage, &format, pool); + if (FAILED(hr)) return hr; + + if ((file_width && width != image_info.Width) + || (file_height && height != image_info.Height) + || (file_depth && depth != image_info.Depth) + || (file_format && format != image_info.Format) + || (file_mip_levels && mip_levels != image_info.MipLevels)) + return D3DERR_NOTAVAILABLE; + + hr = IDirect3DDevice9_GetDeviceCaps(device, &caps); + if (FAILED(hr)) + return D3DERR_INVALIDCALL; + + if (mip_levels > image_info.MipLevels) + { + FIXME("Generation of mipmaps for volume textures is not implemented yet.\n"); + mip_levels = image_info.MipLevels; + } + + dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC); + if (pool == D3DPOOL_DEFAULT && !dynamic_texture) + { + hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, D3DPOOL_SYSTEMMEM, &buftex); + tex = buftex; + } + else + { + hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, pool, &tex); + buftex = NULL; + } + + if (FAILED(hr)) return hr; + + hr = load_volume_texture_from_dds(tex, data, palette, filter, color_key, &image_info); + if (FAILED(hr)) + { + IDirect3DVolumeTexture9_Release(tex); + return hr; + } + + if (buftex) + { + hr = D3DXCreateVolumeTexture(device, width, height, depth, mip_levels, usage, format, pool, &tex); + if (FAILED(hr)) + { + IDirect3DVolumeTexture9_Release(buftex); + return hr; + } + + IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)buftex, (IDirect3DBaseTexture9 *)tex); + IDirect3DVolumeTexture9_Release(buftex); + } + + if (info) + *info = image_info; + + *volume_texture = tex; + return D3D_OK; +} + +static inline void fill_texture(const struct pixel_format_desc *format, BYTE *pos, const D3DXVECTOR4 *value) +{ + DWORD c; + + for (c = 0; c < format->bytes_per_pixel; c++) + pos[c] = 0; + + for (c = 0; c < 4; c++) + { + float comp_value; + DWORD i, v = 0, mask32 = format->bits[c] == 32 ? ~0U : ((1 << format->bits[c]) - 1); + + switch (c) + { + case 0: /* Alpha */ + comp_value = value->w; + break; + case 1: /* Red */ + comp_value = value->x; + break; + case 2: /* Green */ + comp_value = value->y; + break; + case 3: /* Blue */ + comp_value = value->z; + break; + } + + if (format->type == FORMAT_ARGBF16) + v = float_32_to_16(comp_value); + else if (format->type == FORMAT_ARGBF) + v = *(DWORD *)&comp_value; + else if (format->type == FORMAT_ARGB) + v = comp_value * ((1 << format->bits[c]) - 1) + 0.5f; + else + FIXME("Unhandled format type %#x\n", format->type); + + for (i = 0; i < format->bits[c] + format->shift[c]; i += 8) + { + BYTE byte, mask; + + if (format->shift[c] > i) + { + mask = mask32 << (format->shift[c] - i); + byte = (v << (format->shift[c] - i)) & mask; + } + else + { + mask = mask32 >> (i - format->shift[c]); + byte = (v >> (i - format->shift[c])) & mask; + } + pos[i / 8] |= byte; + } + } +} + +HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D function, void *funcdata) +{ + DWORD miplevels; + DWORD m, x, y; + D3DSURFACE_DESC desc; + D3DLOCKED_RECT lock_rect; + D3DXVECTOR4 value; + D3DXVECTOR2 coord, size; + const struct pixel_format_desc *format; + BYTE *data; + + if (texture == NULL || function == NULL) + return D3DERR_INVALIDCALL; + + miplevels = IDirect3DBaseTexture9_GetLevelCount(texture); + + for (m = 0; m < miplevels; m++) + { + if (FAILED(IDirect3DTexture9_GetLevelDesc(texture, m, &desc))) + return D3DERR_INVALIDCALL; + + format = get_format_info(desc.Format); + if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF) + { + FIXME("Unsupported texture format %#x\n", desc.Format); + return D3DERR_INVALIDCALL; + } + + if (FAILED(IDirect3DTexture9_LockRect(texture, m, &lock_rect, NULL, D3DLOCK_DISCARD))) + return D3DERR_INVALIDCALL; + + size.x = 1.0f / desc.Width; + size.y = 1.0f / desc.Height; + + data = lock_rect.pBits; + + for (y = 0; y < desc.Height; y++) + { + /* The callback function expects the coordinates of the center + of the texel */ + coord.y = (y + 0.5f) / desc.Height; + + for (x = 0; x < desc.Width; x++) + { + coord.x = (x + 0.5f) / desc.Width; + + function(&value, &coord, &size, funcdata); + + fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value); + } + } + IDirect3DTexture9_UnlockRect(texture, m); + } + + return D3D_OK; +} + +HRESULT WINAPI D3DXFillTextureTX(struct IDirect3DTexture9 *texture, ID3DXTextureShader *texture_shader) +{ + FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader); + return E_NOTIMPL; +} + +HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device, + const void *src_data, + UINT src_data_size, + UINT size, + UINT mip_levels, + DWORD usage, + D3DFORMAT format, + D3DPOOL pool, + DWORD filter, + DWORD mip_filter, + D3DCOLOR color_key, + D3DXIMAGE_INFO *src_info, + PALETTEENTRY *palette, + IDirect3DCubeTexture9 **cube_texture) +{ + HRESULT hr; + D3DCAPS9 caps; + UINT loaded_miplevels; + D3DXIMAGE_INFO img_info; + BOOL dynamic_texture; + BOOL file_size = FALSE; + BOOL file_format = FALSE; + BOOL file_mip_levels = FALSE; + IDirect3DCubeTexture9 *tex, *buftex; + + TRACE("(%p, %p, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p)\n", device, + src_data, src_data_size, size, mip_levels, usage, format, pool, filter, mip_filter, + color_key, src_info, palette, cube_texture); + + if (!device || !cube_texture || !src_data || !src_data_size) + return D3DERR_INVALIDCALL; + + hr = D3DXGetImageInfoFromFileInMemory(src_data, src_data_size, &img_info); + if (FAILED(hr)) + return hr; + + if (img_info.ImageFileFormat != D3DXIFF_DDS) + return D3DXERR_INVALIDDATA; + + if (img_info.Width != img_info.Height) + return D3DXERR_INVALIDDATA; + + if (size == 0 || size == D3DX_DEFAULT_NONPOW2) + size = img_info.Width; + if (size == D3DX_DEFAULT) + size = make_pow2(img_info.Width); + + if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT) + format = img_info.Format; + + if (size == D3DX_FROM_FILE) + { + file_size = TRUE; + size = img_info.Width; + } + + if (format == D3DFMT_FROM_FILE) + { + file_format = TRUE; + format = img_info.Format; + } + + if (mip_levels == D3DX_FROM_FILE) + { + file_mip_levels = TRUE; + mip_levels = img_info.MipLevels; + } + + hr = D3DXCheckCubeTextureRequirements(device, &size, &mip_levels, usage, &format, pool); + if (FAILED(hr)) + return hr; + + if ((file_size && size != img_info.Width) + || (file_format && format != img_info.Format) + || (file_mip_levels && mip_levels != img_info.MipLevels)) + return D3DERR_NOTAVAILABLE; + + hr = IDirect3DDevice9_GetDeviceCaps(device, &caps); + if (FAILED(hr)) + return D3DERR_INVALIDCALL; + + if (mip_levels > img_info.MipLevels && (D3DFMT_DXT1 <= img_info.Format && img_info.Format <= D3DFMT_DXT5)) + { + FIXME("Generation of mipmaps for compressed pixel formats is not supported yet.\n"); + mip_levels = img_info.MipLevels; + } + + dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC); + if (pool == D3DPOOL_DEFAULT && !dynamic_texture) + { + hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, D3DPOOL_SYSTEMMEM, &buftex); + tex = buftex; + } + else + { + hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, pool, &tex); + buftex = NULL; + } + if (FAILED(hr)) + return hr; + + hr = load_cube_texture_from_dds(tex, src_data, palette, filter, color_key, &img_info); + if (FAILED(hr)) + { + IDirect3DCubeTexture9_Release(tex); + return hr; + } + + loaded_miplevels = min(IDirect3DCubeTexture9_GetLevelCount(tex), img_info.MipLevels); + hr = D3DXFilterTexture((IDirect3DBaseTexture9*) tex, palette, loaded_miplevels - 1, mip_filter); + if (FAILED(hr)) + { + IDirect3DCubeTexture9_Release(tex); + return hr; + } + + if (buftex) + { + hr = D3DXCreateCubeTexture(device, size, mip_levels, usage, format, pool, &tex); + if (FAILED(hr)) + { + IDirect3DCubeTexture9_Release(buftex); + return hr; + } + + IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)buftex, (IDirect3DBaseTexture9 *)tex); + IDirect3DCubeTexture9_Release(buftex); + } + + if (src_info) + *src_info = img_info; + + *cube_texture = tex; + return D3D_OK; +} + + +HRESULT WINAPI D3DXCreateCubeTextureFromFileA(IDirect3DDevice9 *device, + const char *src_filename, + IDirect3DCubeTexture9 **cube_texture) +{ + int len; + HRESULT hr; + WCHAR *filename; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %p): relay\n", device, wine_dbgstr_a(src_filename), cube_texture); + + if (!src_filename) return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, src_filename, -1, NULL, 0); + filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!filename) return E_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, src_filename, -1, filename, len); + + hr = map_view_of_file(filename, &data, &data_size); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, filename); + return D3DXERR_INVALIDDATA; + } + + hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, + 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, cube_texture); + + UnmapViewOfFile(data); + HeapFree(GetProcessHeap(), 0, filename); + return hr; +} + +HRESULT WINAPI D3DXCreateCubeTextureFromFileW(IDirect3DDevice9 *device, + const WCHAR *src_filename, + IDirect3DCubeTexture9 **cube_texture) +{ + HRESULT hr; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %p): relay\n", device, wine_dbgstr_w(src_filename), cube_texture); + + hr = map_view_of_file(src_filename, &data, &data_size); + if (FAILED(hr)) return D3DXERR_INVALIDDATA; + + hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, D3DX_DEFAULT, D3DX_DEFAULT, + 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, cube_texture); + + UnmapViewOfFile(data); + return hr; +} + +HRESULT WINAPI D3DXCreateCubeTextureFromFileExA(IDirect3DDevice9 *device, + const char *src_filename, + UINT size, + UINT mip_levels, + DWORD usage, + D3DFORMAT format, + D3DPOOL pool, + DWORD filter, + DWORD mip_filter, + D3DCOLOR color_key, + D3DXIMAGE_INFO *image_info, + PALETTEENTRY *palette, + IDirect3DCubeTexture9 **cube_texture) +{ + int len; + HRESULT hr; + WCHAR *filename; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n", + device, wine_dbgstr_a(src_filename), size, mip_levels, usage, format, + pool, filter, mip_filter, color_key, image_info, palette, cube_texture); + + if (!src_filename) return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, src_filename, -1, NULL, 0); + filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!filename) return E_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, src_filename, -1, filename, len); + + hr = map_view_of_file(filename, &data, &data_size); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, filename); + return D3DXERR_INVALIDDATA; + } + + hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, size, mip_levels, + usage, format, pool, filter, mip_filter, color_key, image_info, palette, cube_texture); + + UnmapViewOfFile(data); + HeapFree(GetProcessHeap(), 0, filename); + return hr; +} + +HRESULT WINAPI D3DXCreateCubeTextureFromFileExW(IDirect3DDevice9 *device, + const WCHAR *src_filename, + UINT size, + UINT mip_levels, + DWORD usage, + D3DFORMAT format, + D3DPOOL pool, + DWORD filter, + DWORD mip_filter, + D3DCOLOR color_key, + D3DXIMAGE_INFO *image_info, + PALETTEENTRY *palette, + IDirect3DCubeTexture9 **cube_texture) +{ + HRESULT hr; + void *data; + DWORD data_size; + + TRACE("(%p, %s, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): relay\n", + device, wine_dbgstr_w(src_filename), size, mip_levels, usage, format, + pool, filter, mip_filter, color_key, image_info, palette, cube_texture); + + hr = map_view_of_file(src_filename, &data, &data_size); + if (FAILED(hr)) return D3DXERR_INVALIDDATA; + + hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, data, data_size, size, mip_levels, + usage, format, pool, filter, mip_filter, color_key, image_info, palette, cube_texture); + + UnmapViewOfFile(data); + return hr; +} + +enum cube_coord +{ + XCOORD = 0, + XCOORDINV = 1, + YCOORD = 2, + YCOORDINV = 3, + ZERO = 4, + ONE = 5 +}; + +static float get_cube_coord(enum cube_coord coord, unsigned int x, unsigned int y, unsigned int size) +{ + switch (coord) + { + case XCOORD: + return x + 0.5f; + case XCOORDINV: + return size - x - 0.5f; + case YCOORD: + return y + 0.5f; + case YCOORDINV: + return size - y - 0.5f; + case ZERO: + return 0.0f; + case ONE: + return size; + default: + ERR("Unexpected coordinate value\n"); + return 0.0f; + } +} + +HRESULT WINAPI D3DXFillCubeTexture(struct IDirect3DCubeTexture9 *texture, LPD3DXFILL3D function, void *funcdata) +{ + DWORD miplevels; + DWORD m, x, y, f; + D3DSURFACE_DESC desc; + D3DLOCKED_RECT lock_rect; + D3DXVECTOR4 value; + D3DXVECTOR3 coord, size; + const struct pixel_format_desc *format; + BYTE *data; + static const enum cube_coord coordmap[6][3] = + { + {ONE, YCOORDINV, XCOORDINV}, + {ZERO, YCOORDINV, XCOORD}, + {XCOORD, ONE, YCOORD}, + {XCOORD, ZERO, YCOORDINV}, + {XCOORD, YCOORDINV, ONE}, + {XCOORDINV, YCOORDINV, ZERO} + }; + + if (texture == NULL || function == NULL) + return D3DERR_INVALIDCALL; + + miplevels = IDirect3DBaseTexture9_GetLevelCount(texture); + + for (m = 0; m < miplevels; m++) + { + if (FAILED(IDirect3DCubeTexture9_GetLevelDesc(texture, m, &desc))) + return D3DERR_INVALIDCALL; + + format = get_format_info(desc.Format); + if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF) + { + FIXME("Unsupported texture format %#x\n", desc.Format); + return D3DERR_INVALIDCALL; + } + + for (f = 0; f < 6; f++) + { + if (FAILED(IDirect3DCubeTexture9_LockRect(texture, f, m, &lock_rect, NULL, D3DLOCK_DISCARD))) + return D3DERR_INVALIDCALL; + + size.x = (f == 0) || (f == 1) ? 0.0f : 2.0f / desc.Width; + size.y = (f == 2) || (f == 3) ? 0.0f : 2.0f / desc.Width; + size.z = (f == 4) || (f == 5) ? 0.0f : 2.0f / desc.Width; + + data = lock_rect.pBits; + + for (y = 0; y < desc.Height; y++) + { + for (x = 0; x < desc.Width; x++) + { + coord.x = get_cube_coord(coordmap[f][0], x, y, desc.Width) / desc.Width * 2.0f - 1.0f; + coord.y = get_cube_coord(coordmap[f][1], x, y, desc.Width) / desc.Width * 2.0f - 1.0f; + coord.z = get_cube_coord(coordmap[f][2], x, y, desc.Width) / desc.Width * 2.0f - 1.0f; + + function(&value, &coord, &size, funcdata); + + fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value); + } + } + IDirect3DCubeTexture9_UnlockRect(texture, f, m); + } + } + + return D3D_OK; +} + +HRESULT WINAPI D3DXFillCubeTextureTX(struct IDirect3DCubeTexture9 *texture, ID3DXTextureShader *texture_shader) +{ + FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader); + return E_NOTIMPL; +} + +HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LPD3DXFILL3D function, void *funcdata) +{ + DWORD miplevels; + DWORD m, x, y, z; + D3DVOLUME_DESC desc; + D3DLOCKED_BOX lock_box; + D3DXVECTOR4 value; + D3DXVECTOR3 coord, size; + const struct pixel_format_desc *format; + BYTE *data; + + if (texture == NULL || function == NULL) + return D3DERR_INVALIDCALL; + + miplevels = IDirect3DBaseTexture9_GetLevelCount(texture); + + for (m = 0; m < miplevels; m++) + { + if (FAILED(IDirect3DVolumeTexture9_GetLevelDesc(texture, m, &desc))) + return D3DERR_INVALIDCALL; + + format = get_format_info(desc.Format); + if (format->type != FORMAT_ARGB && format->type != FORMAT_ARGBF16 && format->type != FORMAT_ARGBF) + { + FIXME("Unsupported texture format %#x\n", desc.Format); + return D3DERR_INVALIDCALL; + } + + if (FAILED(IDirect3DVolumeTexture9_LockBox(texture, m, &lock_box, NULL, D3DLOCK_DISCARD))) + return D3DERR_INVALIDCALL; + + size.x = 1.0f / desc.Width; + size.y = 1.0f / desc.Height; + size.z = 1.0f / desc.Depth; + + data = lock_box.pBits; + + for (z = 0; z < desc.Depth; z++) + { + /* The callback function expects the coordinates of the center + of the texel */ + coord.z = (z + 0.5f) / desc.Depth; + + for (y = 0; y < desc.Height; y++) + { + coord.y = (y + 0.5f) / desc.Height; + + for (x = 0; x < desc.Width; x++) + { + coord.x = (x + 0.5f) / desc.Width; + + function(&value, &coord, &size, funcdata); + + fill_texture(format, data + z * lock_box.SlicePitch + y * lock_box.RowPitch + + x * format->bytes_per_pixel, &value); + } + } + } + IDirect3DVolumeTexture9_UnlockBox(texture, m); + } + + return D3D_OK; +} + +HRESULT WINAPI D3DXFillVolumeTextureTX(struct IDirect3DVolumeTexture9 *texture, ID3DXTextureShader *texture_shader) +{ + FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader); + return E_NOTIMPL; +} + +HRESULT WINAPI D3DXSaveTextureToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) +{ + int len; + WCHAR *filename; + HRESULT hr; + ID3DXBuffer *buffer; + + TRACE("(%s, %#x, %p, %p): relay\n", + wine_dbgstr_a(dst_filename), file_format, src_texture, src_palette); + + if (!dst_filename) return D3DERR_INVALIDCALL; + + len = MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, NULL, 0); + filename = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!filename) return E_OUTOFMEMORY; + MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len); + + hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, src_texture, src_palette); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(filename, buffer); + ID3DXBuffer_Release(buffer); + } + + HeapFree(GetProcessHeap(), 0, filename); + return hr; +} + +HRESULT WINAPI D3DXSaveTextureToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) +{ + HRESULT hr; + ID3DXBuffer *buffer; + + TRACE("(%s, %#x, %p, %p): relay\n", + wine_dbgstr_w(dst_filename), file_format, src_texture, src_palette); + + if (!dst_filename) return D3DERR_INVALIDCALL; + + hr = D3DXSaveTextureToFileInMemory(&buffer, file_format, src_texture, src_palette); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(dst_filename, buffer); + ID3DXBuffer_Release(buffer); + } + + return hr; +} + +HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) +{ + HRESULT hr; + D3DRESOURCETYPE type; + IDirect3DSurface9 *surface; + + TRACE("(%p, %#x, %p, %p)\n", + dst_buffer, file_format, src_texture, src_palette); + + if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL; + + if (file_format == D3DXIFF_DDS) + return save_dds_texture_to_memory(dst_buffer, src_texture, src_palette); + + type = IDirect3DBaseTexture9_GetType(src_texture); + switch (type) + { + case D3DRTYPE_TEXTURE: + case D3DRTYPE_CUBETEXTURE: + hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface); + break; + case D3DRTYPE_VOLUMETEXTURE: + FIXME("Volume textures aren't supported yet\n"); + return E_NOTIMPL; + default: + return D3DERR_INVALIDCALL; + } + + if (SUCCEEDED(hr)) + { + hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL); + IDirect3DSurface9_Release(surface); + } - return IDirect3DDevice9_CreateTexture(pDevice, width, height, miplevels, usage, format, pool, ppTexture, NULL); + return hr; }