diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index 15d693c..61c4514 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -269,9 +269,9 @@ @ stdcall D3DXSaveTextureToFileA(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stdcall D3DXSaveTextureToFileW(ptr long ptr ptr) -@ stub D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) -@ stub D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileA(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileInMemory(ptr long ptr ptr ptr) +@ stdcall D3DXSaveVolumeToFileW(ptr long ptr ptr ptr) @ stdcall D3DXSHAdd(ptr long ptr ptr) @ stdcall D3DXSHDot(long ptr ptr) @ stdcall D3DXSHEvalConeLight(long ptr float float float float ptr ptr ptr) diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h index 79f3b76..edac24d 100644 --- a/dlls/d3dx9_36/d3dx9_36_private.h +++ b/dlls/d3dx9_36/d3dx9_36_private.h @@ -97,6 +97,10 @@ HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *d const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN; HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, const void *src_data, const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info) DECLSPEC_HIDDEN; +HRESULT save_dds_texture_to_memory(ID3DXBuffer **dst_buffer, IDirect3DBaseTexture9 *src_texture, + const PALETTEENTRY *src_palette) DECLSPEC_HIDDEN; +HRESULT save_dds_volume_to_memory(ID3DXBuffer **dst_buffer, IDirect3DVolume9 *src_volume, + UINT levels, const D3DBOX *src_box) DECLSPEC_HIDDEN; unsigned short float_32_to_16(const float in) DECLSPEC_HIDDEN; float float_16_to_32(const unsigned short in) DECLSPEC_HIDDEN; diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 295ef63..b5636a1 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -77,7 +81,7 @@ static const GUID *d3dformat_to_wic_guid(D3DFORMAT format) /* dds_header.flags */ #define DDS_CAPS 0x1 #define DDS_HEIGHT 0x2 -#define DDS_WIDTH 0x2 +#define DDS_WIDTH 0x4 #define DDS_PITCH 0x8 #define DDS_PIXELFORMAT 0x1000 #define DDS_MIPMAPCOUNT 0x20000 @@ -88,6 +92,7 @@ static const GUID *d3dformat_to_wic_guid(D3DFORMAT format) #define DDS_CAPS_COMPLEX 0x8 #define DDS_CAPS_TEXTURE 0x1000 #define DDS_CAPS_MIPMAP 0x400000 +#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 /* dds_header.caps2 */ #define DDS_CAPS2_CUBEMAP 0x200 @@ -311,6 +316,14 @@ static HRESULT d3dformat_to_dds_pixel_format(struct dds_pixel_format *pixel_form } } + /* Reuse dds_fourcc_to_d3dformat as D3DFORMAT and FOURCC are DWORD with same values */ + if (dds_fourcc_to_d3dformat(d3dformat) != D3DFMT_UNKNOWN) + { + pixel_format->flags |= DDS_PF_FOURCC; + pixel_format->fourcc = d3dformat; + return D3D_OK; + } + WARN("Unknown pixel format %#x\n", d3dformat); return E_NOTIMPL; } @@ -322,19 +335,11 @@ static HRESULT calculate_dds_surface_size(D3DFORMAT format, UINT width, UINT hei if (format_desc->type == FORMAT_UNKNOWN) return E_NOTIMPL; - if (format_desc->block_width != 1 || format_desc->block_height != 1) - { - *pitch = format_desc->block_byte_count + *pitch = format_desc->block_byte_count * max(1, (width + format_desc->block_width - 1) / format_desc->block_width); - *size = *pitch + *size = *pitch * max(1, (height + format_desc->block_height - 1) / format_desc->block_height); - } - else - { - *pitch = width * format_desc->bytes_per_pixel; - *size = *pitch * height; - } - + TRACE("return pitch=%d size=%d\n", *pitch, *size); return D3D_OK; } @@ -389,7 +394,7 @@ static HRESULT get_image_info_from_dds(const void *buffer, UINT length, D3DXIMAG info->Width = header->width; info->Height = header->height; - info->Depth = 1; + info->Depth = header->depth ? header->depth: 1; info->MipLevels = (header->flags & DDS_MIPMAPCOUNT) ? header->miplevels : 1; info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format); @@ -487,13 +492,14 @@ static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSur memset(header, 0, sizeof(*header)); header->signature = MAKEFOURCC('D','D','S',' '); - header->size = sizeof(*header); - header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PITCH | DDS_PIXELFORMAT | DDS_MIPMAPCOUNT; + /* The signature is not really part of the DDS header */ + header->size = sizeof(*header) - sizeof(header->signature); + header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT; + /* Note that native does not set DDS_LINEARSIZE flag nor pitch_or_linear_size field for DXTn */ + header->flags |= (pixel_format->block_width != 1) || (pixel_format->block_height != 1) ? DDS_LINEARSIZE : DDS_PITCH; header->height = src_desc.Height; header->width = src_desc.Width; header->pitch_or_linear_size = dst_pitch; - header->depth = 1; - header->miplevels = 1; header->caps = DDS_CAPS_TEXTURE; hr = d3dformat_to_dds_pixel_format(&header->pixel_format, src_desc.Format); if (FAILED(hr)) @@ -521,6 +527,201 @@ static HRESULT save_dds_surface_to_memory(ID3DXBuffer **dst_buffer, IDirect3DSur return D3D_OK; } +HRESULT save_dds_volume_to_memory(ID3DXBuffer **dst_buffer, IDirect3DVolume9 *src_volume, UINT levels, const D3DBOX *src_box) +{ + HRESULT hr; + UINT dst_pitch, slice_size, file_size; + D3DVOLUME_DESC src_desc; + D3DLOCKED_BOX locked_box; + ID3DXBuffer *buffer; + struct dds_header *header; + BYTE *pixels; + struct volume volume; + const struct pixel_format_desc *pixel_format; + + if (src_box) + { + FIXME("Saving a part of a volume to a DDS file is not implemented yet\n"); + return E_NOTIMPL; + } + + hr = IDirect3DVolume9_GetDesc(src_volume, &src_desc); + if (FAILED(hr)) return hr; + + pixel_format = get_format_info(src_desc.Format); + if (pixel_format->type == FORMAT_UNKNOWN) return E_NOTIMPL; + + file_size = calculate_dds_file_size(src_desc.Format, src_desc.Width, src_desc.Height, src_desc.Depth, levels, 1); + TRACE("format %#x file_size=%d\n", src_desc.Format, file_size); + hr = calculate_dds_surface_size(src_desc.Format, src_desc.Width, src_desc.Height, &dst_pitch, &slice_size); + if (FAILED(hr)) return hr; + + hr = D3DXCreateBuffer(file_size, &buffer); + if (FAILED(hr)) return hr; + + header = ID3DXBuffer_GetBufferPointer(buffer); + pixels = (BYTE *)(header + 1); + + memset(header, 0, sizeof(*header)); + header->signature = MAKEFOURCC('D','D','S',' '); + /* The signature is not really part of the DDS header */ + header->size = sizeof(*header) - sizeof(header->signature); + header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH | DDS_PIXELFORMAT | DDS_MIPMAPCOUNT; + /* Note that native does not set DDS_LINEARSIZE flag nor pitch_or_linear_size field for DXTn */ + header->flags |= (pixel_format->block_width != 1) || (pixel_format->block_height != 1) ? DDS_LINEARSIZE : DDS_PITCH; + header->height = src_desc.Height; + header->width = src_desc.Width; + header->depth = src_desc.Depth; + header->miplevels = levels; + header->pitch_or_linear_size = dst_pitch; + header->caps = DDS_CAPS_TEXTURE; + header->caps2 = DDS_CAPS2_VOLUME; + hr = d3dformat_to_dds_pixel_format(&header->pixel_format, src_desc.Format); + if (FAILED(hr)) + { + ID3DXBuffer_Release(buffer); + return hr; + } + + hr = IDirect3DVolume9_LockBox(src_volume, &locked_box, NULL, D3DLOCK_READONLY); + if (FAILED(hr)) + { + ID3DXBuffer_Release(buffer); + return hr; + } + + volume.width = src_desc.Width; + volume.height = src_desc.Height; + volume.depth = src_desc.Depth; + copy_pixels(locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, pixels, dst_pitch, slice_size, + &volume, pixel_format); + + IDirect3DVolume9_UnlockBox(src_volume); + + *dst_buffer = buffer; + return D3D_OK; +} + +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 save_dds_texture_to_memory(ID3DXBuffer **dst_buffer, IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette) +{ + HRESULT hr = D3DERR_INVALIDCALL; + D3DRESOURCETYPE type; + UINT mip_level; + UINT mip_levels; + UINT src_slice_pitch; + UINT src_row_pitch; + D3DVOLUME_DESC vol_desc; + UINT file_size; + IDirect3DSurface9 *surface = NULL; + IDirect3DVolume9 *volume = NULL; + struct volume volume_box; + D3DLOCKED_BOX locked_box; + ID3DXBuffer *buffer; + struct dds_header *header; + BYTE *pixels = NULL; + const struct pixel_format_desc *pixel_format = NULL; + + type = IDirect3DBaseTexture9_GetType(src_texture); + + if ((type != D3DRTYPE_TEXTURE) && (type != D3DRTYPE_CUBETEXTURE) && (type != D3DRTYPE_VOLUMETEXTURE)) + return D3DERR_INVALIDCALL; + + mip_levels = IDirect3DTexture9_GetLevelCount(src_texture); + + if (src_palette) + { + FIXME("Saving surfaces with palettized pixel formats not implemented yet\n"); + return E_NOTIMPL; + } + + if (type == D3DRTYPE_VOLUMETEXTURE) + { + for (mip_level = 0; mip_level < mip_levels; mip_level++) + { + hr = IDirect3DVolumeTexture9_GetVolumeLevel((IDirect3DVolumeTexture9*)src_texture, mip_level, &volume); + if (FAILED(hr)) break; + + hr = IDirect3DVolume9_GetDesc(volume, &vol_desc); + if (FAILED(hr)) return hr; + if (!mip_level) { + pixel_format = get_format_info(vol_desc.Format); + file_size = calculate_dds_file_size(vol_desc.Format, vol_desc.Width, vol_desc.Height, vol_desc.Depth, mip_levels, 1); + hr = D3DXCreateBuffer(file_size, &buffer); + if (FAILED(hr)) return hr; + header = ID3DXBuffer_GetBufferPointer(buffer); + pixels = (BYTE *)(header + 1); + + memset(header, 0, sizeof(*header)); + header->signature = MAKEFOURCC('D','D','S',' '); + /* The signature is not really part of the DDS header */ + header->size = sizeof(*header) - sizeof(header->signature); + header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_DEPTH | DDS_PIXELFORMAT | DDS_MIPMAPCOUNT; + + //header->flags |= (pixel_format->block_width != 1) || (pixel_format->block_height != 1) ? DDS_LINEARSIZE : DDS_PITCH; + header->height = vol_desc.Height; + header->width = vol_desc.Width; + header->depth = vol_desc.Depth; + header->miplevels = mip_levels; + header->pitch_or_linear_size = 0; //file_size; + header->caps = DDS_CAPS_COMPLEX | DDS_CAPS_TEXTURE | DDS_CAPS_MIPMAP; + header->caps2 = DDS_CAPS2_VOLUME; + hr = d3dformat_to_dds_pixel_format(&header->pixel_format, vol_desc.Format); + if (FAILED(hr)) + { + ID3DXBuffer_Release(buffer); + return hr; + } + } + TRACE("format=%#x W=%d H=%d D=%d\n", vol_desc.Format, vol_desc.Width, vol_desc.Height, vol_desc.Depth); + hr = calculate_dds_surface_size(vol_desc.Format, vol_desc.Width, vol_desc.Height, &src_row_pitch, &src_slice_pitch); + hr = IDirect3DVolume9_LockBox(volume, &locked_box, NULL, D3DLOCK_READONLY); + if (FAILED(hr)) + { + ID3DXBuffer_Release(buffer); + return hr; + } + + volume_box.width = vol_desc.Width; + volume_box.height = vol_desc.Height; + volume_box.depth = vol_desc.Depth; + TRACE("locked.pBits %p RowP=%d SlP=%d\n", locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch); + copy_pixels(locked_box.pBits, locked_box.RowPitch, locked_box.SlicePitch, + pixels, src_row_pitch, src_slice_pitch, + &volume_box, pixel_format); + pixels += src_slice_pitch * vol_desc.Depth; + + IDirect3DVolume9_UnlockBox(volume); + IDirect3DVolume9_Release(volume); + } + *dst_buffer = buffer; + } + else + { + hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface); + + if (SUCCEEDED(hr)) + { + hr = save_dds_surface_to_memory(dst_buffer, surface, NULL); + IDirect3DSurface9_Release(surface); + } + } + return hr; +} HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette, const D3DBOX *dst_box, const void *src_data, const D3DBOX *src_box, DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info) @@ -1502,8 +1703,21 @@ void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, UINT row, slice; BYTE *dst_addr; const BYTE *src_addr; - UINT row_block_count = (size->width + format->block_width - 1) / format->block_width; - UINT row_count = (size->height + format->block_height - 1) / format->block_height; + UINT row_block_count, row_count; + if (!format || !format->block_width || !format->block_height) { + if (format) { + ERR("block undefined for the format %#x\n", format->format); + } else { + ERR("no format\n"); + } + return; + } + if (!size) { + ERR("invalid call\n"); + return; + } + row_block_count = (size->width + format->block_width - 1) / format->block_width; + row_count = (size->height + format->block_height - 1) / format->block_height; for (slice = 0; slice < size->depth; slice++) { diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 38349e2..c71f3a9 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -334,10 +334,10 @@ HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UIN if (fmt->block_width != 1 || fmt->block_height != 1) { - if (w < fmt->block_width) - w = fmt->block_width; - if (h < fmt->block_height) - h = fmt->block_height; + 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))) @@ -659,18 +659,6 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi 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; @@ -1873,10 +1861,7 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE 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; - } + return save_dds_texture_to_memory(dst_buffer, src_texture, src_palette); type = IDirect3DBaseTexture9_GetType(src_texture); switch (type) @@ -1886,7 +1871,7 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE hr = get_surface(type, src_texture, D3DCUBEMAP_FACE_POSITIVE_X, 0, &surface); break; case D3DRTYPE_VOLUMETEXTURE: - FIXME("Volume textures aren't supported yet\n"); + FIXME("Volume textures supported only to dds file format\n"); return E_NOTIMPL; default: return D3DERR_INVALIDCALL; diff --git a/dlls/d3dx9_36/volume.c b/dlls/d3dx9_36/volume.c index fae8542..e8e2a9c 100644 --- a/dlls/d3dx9_36/volume.c +++ b/dlls/d3dx9_36/volume.c @@ -325,3 +329,84 @@ HRESULT WINAPI D3DXLoadVolumeFromVolume(IDirect3DVolume9 *dst_volume, IDirect3DVolume9_UnlockBox(src_volume); return hr; } + + +HRESULT WINAPI D3DXSaveVolumeToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DVolume9 *srcvolume, const PALETTEENTRY *src_palette, const D3DBOX *srcbox) +{ + int len; + WCHAR *filename; + HRESULT hr; + ID3DXBuffer *buffer; + + TRACE("(%s, %#x, %p, %p, %p): relay\n", + wine_dbgstr_a(dst_filename), file_format, srcvolume, src_palette, srcbox); + + 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 = D3DXSaveVolumeToFileInMemory(&buffer, file_format, srcvolume, src_palette, srcbox); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(filename, buffer); + ID3DXBuffer_Release(buffer); + } + + HeapFree(GetProcessHeap(), 0, filename); + return hr; +} + +HRESULT WINAPI D3DXSaveVolumeToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DVolume9 *srcvolume, const PALETTEENTRY *src_palette, const D3DBOX *srcbox) +{ + HRESULT hr; + ID3DXBuffer *buffer; + + TRACE("(%s, %#x, %p, %p, %p): relay\n", + wine_dbgstr_w(dst_filename), file_format, srcvolume, src_palette, srcbox); + + if (!dst_filename) return D3DERR_INVALIDCALL; + + hr = D3DXSaveVolumeToFileInMemory(&buffer, file_format, srcvolume, src_palette, srcbox); + if (SUCCEEDED(hr)) + { + hr = write_buffer_to_file(dst_filename, buffer); + ID3DXBuffer_Release(buffer); + } + + return hr; +} + +HRESULT WINAPI D3DXSaveVolumeToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, + IDirect3DVolume9 *srcvolume, const PALETTEENTRY *src_palette, const D3DBOX *srcbox) +{ + TRACE("(%p, %#x, %p, %p, %p)\n", + dst_buffer, file_format, srcvolume, src_palette, srcbox); + + if (!dst_buffer || !srcvolume) return D3DERR_INVALIDCALL; + + if (src_palette) + { + FIXME("Saving volume with palettized pixel formats is not implemented yet\n"); + return D3DERR_INVALIDCALL; + } + + switch (file_format) + { + case D3DXIFF_DDS: + return save_dds_volume_to_memory(dst_buffer, srcvolume, 1, srcbox); + case D3DXIFF_HDR: + case D3DXIFF_PFM: + case D3DXIFF_TGA: + case D3DXIFF_PPM: + FIXME("File format %#x is not supported yet\n", file_format); + return E_NOTIMPL; + default: + return D3DERR_INVALIDCALL; + } +} + diff --git a/include/d3dx9tex.h b/include/d3dx9tex.h index 542460f..fbe8ae6 100644 --- a/include/d3dx9tex.h +++ b/include/d3dx9tex.h @@ -185,6 +185,8 @@ HRESULT WINAPI D3DXSaveVolumeToFileA(const char *destfile, D3DXIMAGE_FILEFORMAT struct IDirect3DVolume9 *srcvolume, const PALETTEENTRY *srcpalette, const D3DBOX *srcbox); HRESULT WINAPI D3DXSaveVolumeToFileW(const WCHAR *destfile, D3DXIMAGE_FILEFORMAT destformat, struct IDirect3DVolume9 *srcvolume, const PALETTEENTRY *srcpalette, const D3DBOX *srcbox); +HRESULT WINAPI D3DXSaveVolumeToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format, + struct IDirect3DVolume9 *srcvolume, const PALETTEENTRY *srcpalette, const D3DBOX *srcbox); #define D3DXSaveVolumeToFile WINELIB_NAME_AW(D3DXSaveVolumeToFile)