diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h index a6c4fcdc9f2..9405a0f963f 100644 --- a/dlls/d3dx9_36/d3dx9_36_private.h +++ b/dlls/d3dx9_36/d3dx9_36_private.h @@ -62,6 +62,9 @@ HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer, const PixelFormatDesc *get_format_info(D3DFORMAT format) DECLSPEC_HIDDEN; const PixelFormatDesc *get_format_info_idx(int idx) DECLSPEC_HIDDEN; +HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data, + const PALETTEENTRY *palette, DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN; + /* debug helpers */ const char *debug_d3dxparameter_class(D3DXPARAMETER_CLASS c) DECLSPEC_HIDDEN; const char *debug_d3dxparameter_type(D3DXPARAMETER_TYPE t) DECLSPEC_HIDDEN; diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 337b5132bf2..ef4baefd613 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -95,6 +95,9 @@ static const GUID *d3dformat_to_wic_guid(D3DFORMAT format) #define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 #define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 #define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 +#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ + | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ + | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) #define DDS_CAPS2_VOLUME 0x200000 /* dds_pixel_format.flags */ @@ -374,6 +377,59 @@ static HRESULT get_image_info_from_dds(const void *buffer, UINT length, D3DXIMAG return D3D_OK; } +HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data, + const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) +{ + HRESULT hr; + int face; + int mip_level; + UINT size; + RECT src_rect; + UINT src_pitch; + UINT mip_levels; + UINT mip_level_size; + IDirect3DSurface9 *surface; + const struct dds_header *header = src_data; + const BYTE *pixels = (BYTE *)(header + 1); + + if (src_info->ResourceType != D3DRTYPE_CUBETEXTURE) + return D3DXERR_INVALIDDATA; + + if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES) + { + WARN("Only full cubemaps are supported\n"); + return D3DXERR_INVALIDDATA; + } + + mip_levels = min(src_info->MipLevels, IDirect3DCubeTexture9_GetLevelCount(cube_texture)); + for (face = D3DCUBEMAP_FACE_POSITIVE_X; face <= D3DCUBEMAP_FACE_NEGATIVE_Z; face++) + { + size = src_info->Width; + for (mip_level = 0; mip_level < src_info->MipLevels; mip_level++) + { + hr = calculate_dds_surface_size(src_info, size, size, &src_pitch, &mip_level_size); + if (FAILED(hr)) return hr; + + /* if texture has fewer mip levels than DDS file, skip excessive mip levels */ + if (mip_level < mip_levels) + { + SetRect(&src_rect, 0, 0, size, size); + + IDirect3DCubeTexture9_GetCubeMapSurface(cube_texture, face, mip_level, &surface); + hr = D3DXLoadSurfaceFromMemory(surface, palette, NULL, pixels, src_info->Format, src_pitch, + NULL, &src_rect, filter, color_key); + IDirect3DSurface9_Release(surface); + if (FAILED(hr)) return hr; + } + + pixels += mip_level_size; + size = max(1, size / 2); + } + } + + return D3D_OK; +} + /************************************************************ * D3DXGetImageInfoFromFileInMemory * diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index 609b6d88cb1..f3422e63f87 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -1114,37 +1114,35 @@ static void test_D3DXCreateCubeTextureFromFileInMemory(IDirect3DDevice9 *device) IDirect3DCubeTexture9 *cube_texture; D3DSURFACE_DESC surface_desc; - todo_wine { - hr = D3DXCreateCubeTextureFromFileInMemory(NULL, dds_cube_map, sizeof(dds_cube_map), &cube_texture); - ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); + hr = D3DXCreateCubeTextureFromFileInMemory(NULL, dds_cube_map, sizeof(dds_cube_map), &cube_texture); + ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); - hr = D3DXCreateCubeTextureFromFileInMemory(device, NULL, sizeof(dds_cube_map), &cube_texture); - ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); + hr = D3DXCreateCubeTextureFromFileInMemory(device, NULL, sizeof(dds_cube_map), &cube_texture); + ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); - hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, 0, &cube_texture); - ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); + hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, 0, &cube_texture); + ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); - hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), NULL); - ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); + hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), NULL); + ok(hr == D3DERR_INVALIDCALL, "D3DXCreateCubeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); - hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), &cube_texture); - if (SUCCEEDED(hr)) - { - levelcount = IDirect3DCubeTexture9_GetLevelCount(cube_texture); - ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount); + hr = D3DXCreateCubeTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), &cube_texture); + if (SUCCEEDED(hr)) + { + levelcount = IDirect3DCubeTexture9_GetLevelCount(cube_texture); + todo_wine ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount); - hr = IDirect3DCubeTexture9_GetLevelDesc(cube_texture, 0, &surface_desc); - ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK); - ok(surface_desc.Width == 4, "Got width %u, expected 4\n", surface_desc.Width); - ok(surface_desc.Height == 4, "Got height %u, expected 4\n", surface_desc.Height); + hr = IDirect3DCubeTexture9_GetLevelDesc(cube_texture, 0, &surface_desc); + ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK); + ok(surface_desc.Width == 4, "Got width %u, expected 4\n", surface_desc.Width); + ok(surface_desc.Height == 4, "Got height %u, expected 4\n", surface_desc.Height); - hr = IDirect3DCubeTexture9_GetLevelDesc(cube_texture, 3, &surface_desc); - ok(hr == D3DERR_INVALIDCALL, "GetLevelDesc returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); + hr = IDirect3DCubeTexture9_GetLevelDesc(cube_texture, 3, &surface_desc); + todo_wine ok(hr == D3DERR_INVALIDCALL, "GetLevelDesc returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); - ref = IDirect3DCubeTexture9_Release(cube_texture); - ok(ref == 0, "Invalid reference count. Got %u, expected 0\n", ref); - } else skip("Couldn't create cube texture\n"); - } + ref = IDirect3DCubeTexture9_Release(cube_texture); + ok(ref == 0, "Invalid reference count. Got %u, expected 0\n", ref); + } else skip("Couldn't create cube texture\n"); } static void test_D3DXCreateVolumeTextureFromFileInMemory(IDirect3DDevice9 *device) diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 93ac53344ed..001c5a77f8c 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1078,16 +1078,141 @@ HRESULT WINAPI D3DXFillTexture(LPDIRECT3DTEXTURE9 texture, return D3D_OK; } -HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(LPDIRECT3DDEVICE9 pDevice, LPCVOID pSrcData, UINT SrcDataSize, - UINT Size, UINT MipLevels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, DWORD Filter, DWORD MipFilter, D3DCOLOR ColorKey, - D3DXIMAGE_INFO *pSrcInfo, PALETTEENTRY *pPalette, LPDIRECT3DCUBETEXTURE9 *ppCubeTexture) +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) { - FIXME("(%p, %p, %u, %u, %u, %#x, %#x, %#x, %#x, %#x, %#x, %p, %p, %p): stub\n", pDevice, pSrcData, SrcDataSize, Size, MipLevels, - Usage, Format, Pool, Filter, MipFilter, ColorKey, pSrcInfo, pPalette, ppCubeTexture); + HRESULT hr; + D3DCAPS9 caps; + UINT loaded_miplevels; + D3DXIMAGE_INFO img_info; + BOOL file_size = FALSE; + BOOL file_format = FALSE; + BOOL file_mip_levels = FALSE; + IDirect3DCubeTexture9 *tex, *buftex; - return E_NOTIMPL; + 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 not supported yet\n"); + mip_levels = img_info.MipLevels; + } + + if (pool == D3DPOOL_DEFAULT && !((caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && usage == D3DUSAGE_DYNAMIC)) + { + 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(mip_levels, 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)