From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 78 +++++++++++++++++++ dlls/d3dx9_36/surface.c | 86 +++------------------ dlls/d3dx9_36/tests/texture.c | 29 +++----- dlls/d3dx9_36/texture.c | 136 ++++++++++++++++++++++++++++------ 4 files changed, 214 insertions(+), 115 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 7da9f9dd788..0e965eb6017 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -50,6 +50,80 @@ static inline HRESULT d3dx9_handle_load_filter(DWORD *filter) return d3dx9_validate_filter(*filter); }
+#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) + +/* dds_header.flags */ +#define DDS_CAPS 0x1 +#define DDS_HEIGHT 0x2 +#define DDS_WIDTH 0x4 +#define DDS_PITCH 0x8 +#define DDS_PIXELFORMAT 0x1000 +#define DDS_MIPMAPCOUNT 0x20000 +#define DDS_LINEARSIZE 0x80000 +#define DDS_DEPTH 0x800000 + +/* dds_header.caps */ +#define DDSCAPS_ALPHA 0x2 +#define DDS_CAPS_COMPLEX 0x8 +#define DDSCAPS_PALETTE 0x100 +#define DDS_CAPS_TEXTURE 0x1000 +#define DDS_CAPS_MIPMAP 0x400000 + +/* dds_header.caps2 */ +#define DDS_CAPS2_CUBEMAP 0x200 +#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 +#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 +#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 +#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 */ +#define DDS_PF_ALPHA 0x1 +#define DDS_PF_ALPHA_ONLY 0x2 +#define DDS_PF_FOURCC 0x4 +#define DDS_PF_INDEXED 0x20 +#define DDS_PF_RGB 0x40 +#define DDS_PF_YUV 0x200 +#define DDS_PF_LUMINANCE 0x20000 +#define DDS_PF_BUMPLUMINANCE 0x40000 +#define DDS_PF_BUMPDUDV 0x80000 + +struct dds_pixel_format +{ + DWORD size; + DWORD flags; + DWORD fourcc; + DWORD bpp; + DWORD rmask; + DWORD gmask; + DWORD bmask; + DWORD amask; +}; + +struct dds_header +{ + DWORD signature; + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitch_or_linear_size; + DWORD depth; + DWORD miplevels; + DWORD reserved[11]; + struct dds_pixel_format pixel_format; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +}; + struct vec4 { float x, y, z, w; @@ -316,6 +390,10 @@ HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLO IDirect3DSurface9 **temp_surface, BOOL write); HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, IDirect3DSurface9 *temp_surface, BOOL update); +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels); +HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, + enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels); HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, D3DXIMAGE_FILEFORMAT file_format, ID3DXBuffer **dst_buffer); const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format); diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index e5a9207ad91..3af573fb0e9 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -78,80 +78,6 @@ static const GUID *wic_guid_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id return NULL; }
-#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) - -/* dds_header.flags */ -#define DDS_CAPS 0x1 -#define DDS_HEIGHT 0x2 -#define DDS_WIDTH 0x4 -#define DDS_PITCH 0x8 -#define DDS_PIXELFORMAT 0x1000 -#define DDS_MIPMAPCOUNT 0x20000 -#define DDS_LINEARSIZE 0x80000 -#define DDS_DEPTH 0x800000 - -/* dds_header.caps */ -#define DDSCAPS_ALPHA 0x2 -#define DDS_CAPS_COMPLEX 0x8 -#define DDSCAPS_PALETTE 0x100 -#define DDS_CAPS_TEXTURE 0x1000 -#define DDS_CAPS_MIPMAP 0x400000 - -/* dds_header.caps2 */ -#define DDS_CAPS2_CUBEMAP 0x200 -#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 -#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 -#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 -#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 */ -#define DDS_PF_ALPHA 0x1 -#define DDS_PF_ALPHA_ONLY 0x2 -#define DDS_PF_FOURCC 0x4 -#define DDS_PF_INDEXED 0x20 -#define DDS_PF_RGB 0x40 -#define DDS_PF_YUV 0x200 -#define DDS_PF_LUMINANCE 0x20000 -#define DDS_PF_BUMPLUMINANCE 0x40000 -#define DDS_PF_BUMPDUDV 0x80000 - -struct dds_pixel_format -{ - DWORD size; - DWORD flags; - DWORD fourcc; - DWORD bpp; - DWORD rmask; - DWORD gmask; - DWORD bmask; - DWORD amask; -}; - -struct dds_header -{ - DWORD signature; - DWORD size; - DWORD flags; - DWORD height; - DWORD width; - DWORD pitch_or_linear_size; - DWORD depth; - DWORD miplevels; - DWORD reserved[11]; - struct dds_pixel_format pixel_format; - DWORD caps; - DWORD caps2; - DWORD caps3; - DWORD caps4; - DWORD reserved2; -}; - #define TGA_IMAGETYPE_COLORMAPPED 1 #define TGA_IMAGETYPE_TRUECOLOR 2 #define TGA_IMAGETYPE_GRAYSCALE 3 @@ -473,7 +399,7 @@ static HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint return D3D_OK; }
-static uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels) { uint32_t layer_size, row_pitch, slice_pitch, i; @@ -491,7 +417,7 @@ static uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id forma return layer_size; }
-static HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, +HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels) { HRESULT hr; @@ -514,6 +440,14 @@ static HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE r header->depth = size->depth; header->caps2 |= DDS_CAPS2_VOLUME; } + + if (mip_levels > 1) + { + header->flags |= DDS_MIPMAPCOUNT; + header->caps |= (DDS_CAPS_MIPMAP | DDS_CAPS_COMPLEX); + header->miplevels = mip_levels; + } + if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) header->caps |= DDSCAPS_ALPHA; if (header->pixel_format.flags & DDS_PF_INDEXED) diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index 7a489545cb4..0a0843074d3 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -3171,7 +3171,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, (DDSCAPS_TEXTURE | DDSCAPS_PALETTE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX), 0, PALETTED_DDS_FILE_HEADER_SIZE + 21, - .todo_hr = TRUE }, { D3DRTYPE_CUBETEXTURE, D3DFMT_P8, D3DPOOL_SCRATCH, 4, 0, 0, 3, test_palette, D3D_OK, { 32, DDS_PF_INDEXED, 0, 8, 0, 0, 0, 0 }, @@ -3191,7 +3190,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT), 4, 4, 0, 0, 3, (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 84, - .todo_hr = TRUE }, { D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 3, NULL, D3D_OK, { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, @@ -3221,7 +3219,6 @@ static void test_save_texture_to_dds_file(IDirect3DDevice9 *device) { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT), 4, 4, 0, 0, 0, (DDSCAPS_TEXTURE | DDSCAPS_ALPHA), 0, DDS_FILE_HEADER_SIZE + 64, - .todo_hr = TRUE }, { D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, 4, 0, 0, 1, NULL, D3D_OK, { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, @@ -3353,24 +3350,20 @@ static void test_D3DXSaveTextureToFileInMemory(IDirect3DDevice9 *device) } }
- todo_wine { hr = D3DXSaveTextureToFileInMemory(&buffer, D3DXIFF_DDS, (IDirect3DBaseTexture9 *)texture, NULL); ok(hr == D3D_OK, "D3DXSaveTextureToFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); - buffer_size = ID3DXBuffer_GetBufferSize(buffer); - hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); - ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK);
- ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); - ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); - ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); - ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE); - ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); - ID3DXBuffer_Release(buffer); - } - } + buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer); + buffer_size = ID3DXBuffer_GetBufferSize(buffer); + hr = D3DXGetImageInfoFromFileInMemory(buffer_pointer, buffer_size, &info); + ok(hr == D3D_OK, "D3DXGetImageInfoFromFileInMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + + ok(info.Width == 256, "Got width %u, expected %u\n", info.Width, 256); + ok(info.Height == 256, "Got height %u, expected %u\n", info.Height, 256); + ok(info.MipLevels == 9, "Got miplevels %u, expected %u\n", info.MipLevels, 9); + ok(info.ResourceType == D3DRTYPE_TEXTURE, "Got resource type %#x, expected %#x\n", info.ResourceType, D3DRTYPE_TEXTURE); + ok(info.ImageFileFormat == D3DXIFF_DDS, "Got file format %#x, expected %#x\n", info.ImageFileFormat, D3DXIFF_DDS); + ID3DXBuffer_Release(buffer);
IDirect3DTexture9_Release(texture);
diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 4b4192dc8b6..55419fbf1ba 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1856,25 +1856,39 @@ HRESULT WINAPI D3DXSaveTextureToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) { - HRESULT hr; + const struct pixel_format_desc *fmt_desc = NULL; + unsigned int levels, file_size, i; + struct d3dx_image image = { 0 }; D3DRESOURCETYPE type; + ID3DXBuffer *buffer; + struct volume size; + HRESULT hr;
TRACE("dst_buffer %p, file_format %u, src_texture %p, src_palette %p.\n", dst_buffer, file_format, src_texture, src_palette);
- if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL; - - if (file_format == D3DXIFF_DDS) - { - FIXME("DDS file format isn't supported yet\n"); - return E_NOTIMPL; - } + if (!dst_buffer || !src_texture || file_format > D3DXIFF_PFM) + return D3DERR_INVALIDCALL;
+ *dst_buffer = buffer = NULL; type = IDirect3DBaseTexture9_GetType(src_texture); - switch (type) + if (type < D3DRTYPE_TEXTURE || type > D3DRTYPE_CUBETEXTURE) + return D3DERR_INVALIDCALL; + + if (file_format != D3DXIFF_DDS) { - case D3DRTYPE_TEXTURE: - case D3DRTYPE_CUBETEXTURE: + if (type == D3DRTYPE_VOLUMETEXTURE) + { + IDirect3DVolume9 *volume; + + hr = IDirect3DVolumeTexture9_GetVolumeLevel((IDirect3DVolumeTexture9 *)src_texture, 0, &volume); + if (SUCCEEDED(hr)) + { + hr = D3DXSaveVolumeToFileInMemory(dst_buffer, file_format, volume, src_palette, NULL); + IDirect3DVolume9_Release(volume); + } + } + else { IDirect3DSurface9 *surface;
@@ -1884,26 +1898,106 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE hr = D3DXSaveSurfaceToFileInMemory(dst_buffer, file_format, surface, src_palette, NULL); IDirect3DSurface9_Release(surface); } - break; }
- case D3DRTYPE_VOLUMETEXTURE: + return hr; + } + + levels = IDirect3DBaseTexture9_GetLevelCount(src_texture); + switch (type) + { + case D3DRTYPE_TEXTURE: { - IDirect3DVolume9 *volume; + IDirect3DTexture9 *texture = (IDirect3DTexture9 *)src_texture; + D3DSURFACE_DESC desc;
- hr = IDirect3DVolumeTexture9_GetVolumeLevel((IDirect3DVolumeTexture9 *)src_texture, 0, &volume); - if (SUCCEEDED(hr)) - { - hr = D3DXSaveVolumeToFileInMemory(dst_buffer, file_format, volume, src_palette, NULL); - IDirect3DVolume9_Release(volume); - } + hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); + if (FAILED(hr)) + break; + + fmt_desc = get_format_info(desc.Format); + if (is_unknown_format(fmt_desc)) + return E_NOTIMPL; + + set_volume_struct(&size, desc.Width, desc.Height, 1); break; }
default: - return D3DERR_INVALIDCALL; + return E_NOTIMPL; }
+ if (is_index_format(fmt_desc) && !src_palette) + return E_NOTIMPL; + + file_size = d3dx_calculate_layer_pixels_size(fmt_desc->format, size.width, size.height, size.depth, levels); + file_size += is_index_format(fmt_desc) ? sizeof(struct dds_header) + DDS_PALETTE_SIZE : sizeof(struct dds_header); + + hr = D3DXCreateBuffer(file_size, &buffer); + if (FAILED(hr)) + return hr; + + hr = d3dx_init_dds_header((struct dds_header *)ID3DXBuffer_GetBufferPointer(buffer), type, fmt_desc->format, &size, + levels); + if (FAILED(hr)) + goto exit; + + if (is_index_format(fmt_desc)) + memcpy((uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(struct dds_header), src_palette, + DDS_PALETTE_SIZE); + + hr = d3dx_image_init(ID3DXBuffer_GetBufferPointer(buffer), ID3DXBuffer_GetBufferSize(buffer), &image, 0, 0); + if (FAILED(hr)) + goto exit; + + for (i = 0; i < levels; ++i) + { + IDirect3DSurface9 *src_surface, *tmp_surface; + struct d3dx_pixels src_pixels, dst_pixels; + D3DSURFACE_DESC src_surface_desc; + D3DLOCKED_RECT src_locked_rect; + RECT src_rect; + + hr = d3dx_image_get_pixels(&image, 0, i, &dst_pixels); + if (FAILED(hr)) + goto exit; + + hr = get_surface(type, src_texture, 0, i, &src_surface); + if (FAILED(hr)) + goto exit; + + hr = lock_surface(src_surface, NULL, &src_locked_rect, &tmp_surface, FALSE); + if (FAILED(hr)) + { + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + IDirect3DTexture9_GetLevelDesc((IDirect3DTexture9 *)src_texture, i, &src_surface_desc); + SetRect(&src_rect, 0, 0, src_surface_desc.Width, src_surface_desc.Height); + set_d3dx_pixels(&src_pixels, src_locked_rect.pBits, src_locked_rect.Pitch, 0, src_palette, + src_surface_desc.Width, src_surface_desc.Height, 1, &src_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, fmt_desc, &src_pixels, fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + { + unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + goto exit; + } + + hr = unlock_surface(src_surface, NULL, tmp_surface, FALSE); + IDirect3DSurface9_Release(src_surface); + if (FAILED(hr)) + goto exit; + } + + *dst_buffer = buffer; + +exit: + if (buffer && (buffer != *dst_buffer)) + ID3DXBuffer_Release(buffer); + return hr; }