#include "d3dx9_36_private.h"
#include <ole2.h>
+#include <wine/wined3d.h>
#include <initguid.h>
#include <wincodec.h>
{ &GUID_WICPixelFormat8bppIndexed, D3DFMT_P8 },
{ &GUID_WICPixelFormat1bppIndexed, D3DFMT_P8 },
{ &GUID_WICPixelFormat4bppIndexed, D3DFMT_P8 },
+ { &GUID_WICPixelFormat8bppGray, D3DFMT_L8 },
{ &GUID_WICPixelFormat16bppBGR555, D3DFMT_X1R5G5B5 },
{ &GUID_WICPixelFormat16bppBGR565, D3DFMT_R5G6B5 },
{ &GUID_WICPixelFormat24bppBGR, D3DFMT_R8G8B8 },
/* 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
#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
{
unsigned int i;
static const DWORD known_fourcc[] = {
- MAKEFOURCC('U','Y','V','Y'),
- MAKEFOURCC('Y','U','Y','2'),
- MAKEFOURCC('R','G','B','G'),
- MAKEFOURCC('G','R','G','B'),
- MAKEFOURCC('D','X','T','1'),
- MAKEFOURCC('D','X','T','2'),
- MAKEFOURCC('D','X','T','3'),
- MAKEFOURCC('D','X','T','4'),
- MAKEFOURCC('D','X','T','5'),
+ D3DFMT_UYVY,
+ D3DFMT_YUY2,
+ D3DFMT_R8G8_B8G8,
+ D3DFMT_G8R8_G8B8,
+ D3DFMT_DXT1,
+ D3DFMT_DXT2,
+ D3DFMT_DXT3,
+ D3DFMT_DXT4,
+ D3DFMT_DXT5,
D3DFMT_R16F,
D3DFMT_G16R16F,
D3DFMT_A16B16G16R16F,
return D3DFMT_UNKNOWN;
}
+static D3DFORMAT dds_bump_luminance_to_d3dformat(const struct dds_pixel_format *pixel_format)
+{
+ if (pixel_format->bpp == 32 && pixel_format->rmask == 0x000000ff && pixel_format->gmask == 0x0000ff00
+ && pixel_format->bmask == 0x00ff0000)
+ return D3DFMT_X8L8V8U8;
+
+ WARN("Unknown bump pixel format (%u, %#x, %#x, %#x, %#x)\n", pixel_format->bpp,
+ pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask);
+ return D3DFMT_UNKNOWN;
+}
+
static D3DFORMAT dds_pixel_format_to_d3dformat(const struct dds_pixel_format *pixel_format)
{
TRACE("pixel_format: size %u, flags %#x, fourcc %#x, bpp %u.\n", pixel_format->size,
return dds_alpha_to_d3dformat(pixel_format);
if (pixel_format->flags & DDS_PF_BUMPDUDV)
return dds_bump_to_d3dformat(pixel_format);
+ if (pixel_format->flags & DDS_PF_BUMPLUMINANCE)
+ return dds_bump_luminance_to_d3dformat(pixel_format);
WARN("Unknown pixel format (flags %#x, fourcc %#x, bpp %u, r %#x, g %#x, b %#x, a %#x)\n",
pixel_format->flags, pixel_format->fourcc, pixel_format->bpp,
}
}
+ /* 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;
}
info->Width = header->width;
info->Height = header->height;
info->Depth = 1;
- info->MipLevels = (header->flags & DDS_MIPMAPCOUNT) ? header->miplevels : 1;
+ info->MipLevels = header->miplevels ? header->miplevels : 1;
info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format);
if (info->Format == D3DFMT_UNKNOWN)
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) - FIELD_OFFSET(struct dds_header, size);
+ header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT;
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))
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;
+ D3DRESOURCETYPE type;
+ UINT mip_levels;
+ IDirect3DSurface9 *surface;
+
+ type = IDirect3DBaseTexture9_GetType(src_texture);
+
+ if ((type != D3DRTYPE_TEXTURE) && (type != D3DRTYPE_CUBETEXTURE) && (type != D3DRTYPE_VOLUMETEXTURE))
+ return D3DERR_INVALIDCALL;
+
+ if (type == D3DRTYPE_CUBETEXTURE)
+ {
+ FIXME("Cube texture not supported yet\n");
+ return E_NOTIMPL;
+ }
+ else if (type == D3DRTYPE_VOLUMETEXTURE)
+ {
+ FIXME("Volume texture not supported yet\n");
+ return E_NOTIMPL;
+ }
+
+ mip_levels = IDirect3DTexture9_GetLevelCount(src_texture);
+
+ if (mip_levels > 1)
+ {
+ FIXME("Mipmap not supported yet\n");
+ return E_NOTIMPL;
+ }
+
+ if (src_palette)
+ {
+ FIXME("Saving surfaces with palettized pixel formats not implemented yet\n");
+ return E_NOTIMPL;
+ }
+
+ 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)
}
}
+ /* For 32 bpp BMP, windowscodecs.dll never returns a format with alpha while
+ * d3dx9_xx.dll returns one if at least 1 pixel has a non zero alpha component */
+ if (SUCCEEDED(hr) && (info->Format == D3DFMT_X8R8G8B8) && (info->ImageFileFormat == D3DXIFF_BMP)) {
+ DWORD size = sizeof(DWORD) * info->Width * info->Height;
+ BYTE *buffer = HeapAlloc(GetProcessHeap(), 0, size);
+ hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, sizeof(DWORD) * info->Width, size, buffer);
+ if (SUCCEEDED(hr)) {
+ DWORD i;
+ for (i = 0; i < info->Width * info->Height; i++) {
+ if (buffer[i*4+3]) {
+ info->Format = D3DFMT_A8R8G8B8;
+ break;
+ }
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
+
if (frame)
IWICBitmapFrameDecode_Release(frame);
*
* RETURNS
* Success: D3D_OK
- * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcData or SrcDataSize are NULL
+ * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL
* D3DXERR_INVALIDDATA, if pSrcData is no valid image file
*
*/
* Extracts the relevant components from the source color and
* drops the less significant bits if they aren't used by the destination format.
*/
-static void get_relevant_argb_components(const struct argb_conversion_info *info, DWORD col, DWORD *out)
+static void get_relevant_argb_components(const struct argb_conversion_info *info, const BYTE *col, DWORD *out)
{
- UINT i = 0;
- for(;i < 4;i++)
- if(info->process_channel[i])
- out[i] = (col & info->srcmask[i]) >> info->srcshift[i];
+ unsigned int i, j;
+ unsigned int component, mask;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if (!info->process_channel[i])
+ continue;
+
+ component = 0;
+ mask = info->srcmask[i];
+ for (j = 0; j < 4 && mask; ++j)
+ {
+ if (info->srcshift[i] < j * 8)
+ component |= (col[j] & mask) << (j * 8 - info->srcshift[i]);
+ else
+ component |= (col[j] & mask) >> (info->srcshift[i] - j * 8);
+ mask >>= 8;
+ }
+ out[i] = component;
+ }
}
/************************************************************
* Copies the source buffer to the destination buffer, performing
* any necessary format conversion and color keying.
* Pixels outsize the source rect are blacked out.
- * Works only for ARGB formats with 1 - 4 bytes per pixel.
*/
void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size,
const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch,
for (x = 0; x < min_width; x++) {
if (!src_format->to_rgba && !dst_format->from_rgba
+ && src_format->type == dst_format->type
&& src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4)
{
DWORD val;
- get_relevant_argb_components(&conv_info, *(DWORD *)src_ptr, channels);
+ get_relevant_argb_components(&conv_info, src_ptr, channels);
val = make_argb_color(&conv_info, channels);
if (color_key)
{
DWORD ck_pixel;
- get_relevant_argb_components(&ck_conv_info, *(DWORD *)src_ptr, channels);
+ get_relevant_argb_components(&ck_conv_info, src_ptr, channels);
ck_pixel = make_argb_color(&ck_conv_info, channels);
if (ck_pixel == color_key)
val &= ~conv_info.destmask[0];
* Copies the source buffer to the destination buffer, performing
* any necessary format conversion, color keying and stretching
* using a point filter.
- * Works only for ARGB formats with 1 - 4 bytes per pixel.
*/
void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size,
const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch,
const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel;
if (!src_format->to_rgba && !dst_format->from_rgba
+ && src_format->type == dst_format->type
&& src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4)
{
DWORD val;
- get_relevant_argb_components(&conv_info, *(DWORD *)src_ptr, channels);
+ get_relevant_argb_components(&conv_info, src_ptr, channels);
val = make_argb_color(&conv_info, channels);
if (color_key)
{
DWORD ck_pixel;
- get_relevant_argb_components(&ck_conv_info, *(DWORD *)src_ptr, channels);
+ get_relevant_argb_components(&ck_conv_info, src_ptr, channels);
ck_pixel = make_argb_color(&ck_conv_info, channels);
if (ck_pixel == color_key)
val &= ~conv_info.destmask[0];
}
}
+typedef BOOL (*dxtn_conversion_func)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+ enum wined3d_format_id format, unsigned int w, unsigned int h);
+
+static dxtn_conversion_func get_dxtn_conversion_func(D3DFORMAT format, BOOL encode)
+{
+ switch (format)
+ {
+ case D3DFMT_DXT1:
+ if (!wined3d_dxtn_supported()) return NULL;
+ return encode ? wined3d_dxt1_encode : wined3d_dxt1_decode;
+ case D3DFMT_DXT3:
+ if (!wined3d_dxtn_supported()) return NULL;
+ return encode ? wined3d_dxt3_encode : wined3d_dxt3_decode;
+ case D3DFMT_DXT5:
+ if (!wined3d_dxtn_supported()) return NULL;
+ return encode ? wined3d_dxt5_encode : wined3d_dxt5_decode;
+ default:
+ return NULL;
+ }
+}
+
/************************************************************
* D3DXLoadSurfaceFromMemory
*
* RETURNS
* Success: D3D_OK, if we successfully load the pixel data into our surface or
* if pSrcMemory is NULL but the other parameters are valid
- * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or
+ * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect is NULL or
* if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) or
* if DestRect is invalid
* D3DXERR_INVALIDDATA, if we fail to lock pDestSurface
D3DSURFACE_DESC surfdesc;
D3DLOCKED_RECT lockrect;
struct volume src_size, dst_size;
+ HRESULT ret = D3D_OK;
- TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s %#x, 0x%08x)\n",
+ TRACE("(%p, %p, %s, %p, %#x, %u, %p, %s, %#x, 0x%08x)\n",
dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_memory, src_format,
src_pitch, src_palette, wine_dbgstr_rect(src_rect), filter, color_key);
}
else /* Stretching or format conversion. */
{
- if (((srcformatdesc->type != FORMAT_ARGB) && (srcformatdesc->type != FORMAT_INDEX)) ||
- (destformatdesc->type != FORMAT_ARGB))
+ dxtn_conversion_func pre_convert, post_convert;
+ void *tmp_src_memory = NULL, *tmp_dst_memory = NULL;
+ UINT tmp_src_pitch, tmp_dst_pitch;
+
+ pre_convert = get_dxtn_conversion_func(srcformatdesc->format, FALSE);
+ post_convert = get_dxtn_conversion_func(destformatdesc->format, TRUE);
+
+ if ((!pre_convert && !is_conversion_from_supported(srcformatdesc)) ||
+ (!post_convert && !is_conversion_to_supported(destformatdesc)))
{
- FIXME("Format conversion missing %#x -> %#x\n", src_format, surfdesc.Format);
+ FIXME("Unsupported format conversion %#x -> %#x.\n", src_format, surfdesc.Format);
return E_NOTIMPL;
}
if (FAILED(IDirect3DSurface9_LockRect(dst_surface, &lockrect, dst_rect, 0)))
return D3DXERR_INVALIDDATA;
+ /* handle pre-conversion */
+ if (pre_convert)
+ {
+ tmp_src_memory = HeapAlloc(GetProcessHeap(), 0, src_size.width * src_size.height * sizeof(DWORD));
+ if (!tmp_src_memory)
+ {
+ ret = E_OUTOFMEMORY;
+ goto error;
+ }
+ tmp_src_pitch = src_size.width * sizeof(DWORD);
+ if (!pre_convert(src_memory, tmp_src_memory, src_pitch, tmp_src_pitch,
+ WINED3DFMT_B8G8R8A8_UNORM, src_size.width, src_size.height))
+ {
+ ret = E_FAIL;
+ goto error;
+ }
+ srcformatdesc = get_format_info(D3DFMT_A8R8G8B8);
+ }
+ else
+ {
+ tmp_src_memory = (void *)src_memory;
+ tmp_src_pitch = src_pitch;
+ }
+
+ /* handle post-conversion */
+ if (post_convert)
+ {
+ tmp_dst_memory = HeapAlloc(GetProcessHeap(), 0, dst_size.width * dst_size.height * sizeof(DWORD));
+ if (!tmp_dst_memory)
+ {
+ ret = E_OUTOFMEMORY;
+ goto error;
+ }
+ tmp_dst_pitch = dst_size.width * sizeof(DWORD);
+ destformatdesc = get_format_info(D3DFMT_A8R8G8B8);
+ }
+ else
+ {
+ tmp_dst_memory = lockrect.pBits;
+ tmp_dst_pitch = lockrect.Pitch;
+ }
+
if ((filter & 0xf) == D3DX_FILTER_NONE)
{
- convert_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc,
- lockrect.pBits, lockrect.Pitch, 0, &dst_size, destformatdesc, color_key, src_palette);
+ convert_argb_pixels(tmp_src_memory, tmp_src_pitch, 0, &src_size, srcformatdesc,
+ tmp_dst_memory, tmp_dst_pitch, 0, &dst_size, destformatdesc, color_key, src_palette);
}
else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */
{
/* Always apply a point filter until D3DX_FILTER_LINEAR,
* D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */
- point_filter_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc,
- lockrect.pBits, lockrect.Pitch, 0, &dst_size, destformatdesc, color_key, src_palette);
+ point_filter_argb_pixels(tmp_src_memory, tmp_src_pitch, 0, &src_size, srcformatdesc,
+ tmp_dst_memory, tmp_dst_pitch, 0, &dst_size, destformatdesc, color_key, src_palette);
+ }
+
+ /* handle post-conversion */
+ if (post_convert)
+ {
+ if (!post_convert(tmp_dst_memory, lockrect.pBits, tmp_dst_pitch, lockrect.Pitch,
+ WINED3DFMT_B8G8R8A8_UNORM, dst_size.width, dst_size.height))
+ {
+ ret = E_FAIL;
+ goto error;
+ }
}
+error:
+ if (pre_convert)
+ HeapFree(GetProcessHeap(), 0, tmp_src_memory);
+ if (post_convert)
+ HeapFree(GetProcessHeap(), 0, tmp_dst_memory);
IDirect3DSurface9_UnlockRect(dst_surface);
}
- return D3D_OK;
+ return ret;
}
/************************************************************
*
* RETURNS
* Success: D3D_OK
- * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface are NULL
+ * Failure: D3DERR_INVALIDCALL, if pDestSurface or pSrcSurface is NULL
* D3DXERR_INVALIDDATA, if one of the surfaces is not lockable
*
*/
if (src_palette)
{
- FIXME("Saving surfaces with palettized pixel formats not implemented yet\n");
+ FIXME("Saving surfaces with palettized pixel formats is not implemented yet\n");
return D3DERR_INVALIDCALL;
}
src_format_desc = get_format_info(src_surface_desc.Format);
dst_format_desc = get_format_info(d3d_pixel_format);
- if (src_format_desc->type != FORMAT_ARGB || dst_format_desc->type != FORMAT_ARGB)
+ if (!is_conversion_from_supported(src_format_desc)
+ || !is_conversion_to_supported(dst_format_desc))
{
- FIXME("Unsupported pixel format conversion %#x -> %#x\n",
+ FIXME("Unsupported format conversion %#x -> %#x.\n",
src_surface_desc.Format, d3d_pixel_format);
hr = E_NOTIMPL;
goto cleanup;