d3dx9: Implement D3DXSaveSurfaceToFileInMemory.

This commit is contained in:
Józef Kucia 2012-05-29 11:29:22 +02:00 committed by Alexandre Julliard
parent d770297c37
commit 70b1bff695
6 changed files with 128 additions and 24 deletions

View File

@ -264,7 +264,7 @@
@ stub D3DXSavePRTCompBufferToFileA(ptr ptr) @ stub D3DXSavePRTCompBufferToFileA(ptr ptr)
@ stub D3DXSavePRTCompBufferToFileW(ptr ptr) @ stub D3DXSavePRTCompBufferToFileW(ptr ptr)
@ stdcall D3DXSaveSurfaceToFileA(ptr long ptr ptr ptr) @ stdcall D3DXSaveSurfaceToFileA(ptr long ptr ptr ptr)
@ stub D3DXSaveSurfaceToFileInMemory(ptr long ptr ptr ptr) @ stdcall D3DXSaveSurfaceToFileInMemory(ptr long ptr ptr ptr)
@ stdcall D3DXSaveSurfaceToFileW(ptr long ptr ptr ptr) @ stdcall D3DXSaveSurfaceToFileW(ptr long ptr ptr ptr)
@ stub D3DXSaveTextureToFileA(ptr long ptr ptr) @ stub D3DXSaveTextureToFileA(ptr long ptr ptr)
@ stub D3DXSaveTextureToFileInMemory(ptr long ptr ptr) @ stub D3DXSaveTextureToFileInMemory(ptr long ptr ptr)

View File

@ -59,6 +59,8 @@ typedef struct _PixelFormatDesc {
HRESULT map_view_of_file(LPCWSTR filename, LPVOID *buffer, DWORD *length) DECLSPEC_HIDDEN; HRESULT map_view_of_file(LPCWSTR filename, LPVOID *buffer, DWORD *length) DECLSPEC_HIDDEN;
HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer, DWORD *length) DECLSPEC_HIDDEN; HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer, DWORD *length) DECLSPEC_HIDDEN;
HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBuffer *buffer) DECLSPEC_HIDDEN;
const PixelFormatDesc *get_format_info(D3DFORMAT format) DECLSPEC_HIDDEN; const PixelFormatDesc *get_format_info(D3DFORMAT format) DECLSPEC_HIDDEN;
const PixelFormatDesc *get_format_info_idx(int idx) DECLSPEC_HIDDEN; const PixelFormatDesc *get_format_info_idx(int idx) DECLSPEC_HIDDEN;

View File

@ -23,6 +23,7 @@
#include "d3dx9_36_private.h" #include "d3dx9_36_private.h"
#include "initguid.h" #include "initguid.h"
#include "ole2.h"
#include "wincodec.h" #include "wincodec.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3dx); WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@ -1584,6 +1585,7 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO
int len; int len;
WCHAR *filename; WCHAR *filename;
HRESULT hr; HRESULT hr;
ID3DXBuffer *buffer;
TRACE("(%s, %#x, %p, %p, %s): relay\n", TRACE("(%s, %#x, %p, %p, %s): relay\n",
wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); wine_dbgstr_a(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
@ -1595,7 +1597,12 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO
if (!filename) return E_OUTOFMEMORY; if (!filename) return E_OUTOFMEMORY;
MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len); MultiByteToWideChar(CP_ACP, 0, dst_filename, -1, filename, len);
hr = D3DXSaveSurfaceToFileW(filename, file_format, src_surface, src_palette, src_rect); hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect);
if (SUCCEEDED(hr))
{
hr = write_buffer_to_file(filename, buffer);
ID3DXBuffer_Release(buffer);
}
HeapFree(GetProcessHeap(), 0, filename); HeapFree(GetProcessHeap(), 0, filename);
return hr; return hr;
@ -1604,11 +1611,31 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO
HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format, HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect) IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
{ {
IWICImagingFactory *factory; HRESULT hr;
ID3DXBuffer *buffer;
TRACE("(%s, %#x, %p, %p, %s): relay\n",
wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
if (!dst_filename) return D3DERR_INVALIDCALL;
hr = D3DXSaveSurfaceToFileInMemory(&buffer, file_format, src_surface, src_palette, src_rect);
if (SUCCEEDED(hr))
{
hr = write_buffer_to_file(dst_filename, buffer);
ID3DXBuffer_Release(buffer);
}
return hr;
}
HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_FILEFORMAT file_format,
IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
{
IWICBitmapEncoder *encoder = NULL; IWICBitmapEncoder *encoder = NULL;
IWICBitmapFrameEncode *frame = NULL; IWICBitmapFrameEncode *frame = NULL;
IPropertyBag2 *encoder_options = NULL; IPropertyBag2 *encoder_options = NULL;
IWICStream *stream = NULL; IStream *stream = NULL;
HRESULT hr; HRESULT hr;
HRESULT initresult; HRESULT initresult;
const CLSID *encoder_clsid; const CLSID *encoder_clsid;
@ -1618,11 +1645,15 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
D3DSURFACE_DESC src_surface_desc; D3DSURFACE_DESC src_surface_desc;
D3DLOCKED_RECT locked_rect; D3DLOCKED_RECT locked_rect;
int width, height; int width, height;
STATSTG stream_stats;
HGLOBAL stream_hglobal;
ID3DXBuffer *buffer;
DWORD size;
TRACE("(%s, %#x, %p, %p, %s)\n", TRACE("(%p, %#x, %p, %p, %s)\n",
wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect)); dst_buffer, file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
if (!dst_filename || !src_surface) return D3DERR_INVALIDCALL; if (!dst_buffer || !src_surface) return D3DERR_INVALIDCALL;
if (src_palette) if (src_palette)
{ {
@ -1657,7 +1688,10 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
if (src_rect) if (src_rect)
{ {
if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom) if (src_rect->left == src_rect->right || src_rect->top == src_rect->bottom)
return D3D_OK; {
WARN("Invalid rectangle with 0 area\n");
return D3DXCreateBuffer(64, dst_buffer);
}
if (src_rect->left < 0 || src_rect->top < 0) if (src_rect->left < 0 || src_rect->top < 0)
return D3DERR_INVALIDCALL; return D3DERR_INVALIDCALL;
if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom) if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom)
@ -1676,24 +1710,14 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); initresult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICImagingFactory, (void **)&factory);
if (FAILED(hr)) goto cleanup_err;
hr = IWICImagingFactory_CreateStream(factory, &stream);
IWICImagingFactory_Release(factory);
if (FAILED(hr)) goto cleanup_err;
hr = IWICStream_InitializeFromFilename(stream, dst_filename, GENERIC_WRITE);
if (FAILED(hr)) goto cleanup_err;
hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER, hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICBitmapEncoder, (void **)&encoder); &IID_IWICBitmapEncoder, (void **)&encoder);
if (FAILED(hr)) goto cleanup_err; if (FAILED(hr)) goto cleanup_err;
hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)stream, WICBitmapEncoderNoCache); hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
IStream_Release((IStream *)stream); if (FAILED(hr)) goto cleanup_err;
stream = NULL;
hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
if (FAILED(hr)) goto cleanup_err; if (FAILED(hr)) goto cleanup_err;
hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options); hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options);
@ -1783,11 +1807,37 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
} }
else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format); else WARN("Unsupported pixel format %#x\n", src_surface_desc.Format);
/* copy data from stream to ID3DXBuffer */
hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME);
if (FAILED(hr)) goto cleanup_err;
if (stream_stats.cbSize.u.HighPart != 0)
{
hr = D3DXERR_INVALIDDATA;
goto cleanup;
}
size = stream_stats.cbSize.u.LowPart;
hr = D3DXCreateBuffer(size, &buffer);
if (FAILED(hr)) goto cleanup;
hr = GetHGlobalFromStream(stream, &stream_hglobal);
if (SUCCEEDED(hr))
{
void *buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
void *stream_data = GlobalLock(stream_hglobal);
memcpy(buffer_pointer, stream_data, size);
GlobalUnlock(stream_hglobal);
*dst_buffer = buffer;
}
else ID3DXBuffer_Release(buffer);
cleanup_err: cleanup_err:
if (FAILED(hr)) hr = D3DERR_INVALIDCALL; if (FAILED(hr) && hr != E_OUTOFMEMORY)
hr = D3DERR_INVALIDCALL;
cleanup: cleanup:
if (stream) IStream_Release((IStream *)stream); if (stream) IStream_Release(stream);
if (frame) IWICBitmapFrameEncode_Release(frame); if (frame) IWICBitmapFrameEncode_Release(frame);
if (encoder_options) IPropertyBag2_Release(encoder_options); if (encoder_options) IPropertyBag2_Release(encoder_options);

View File

@ -920,6 +920,32 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
if(testbitmap_ok) DeleteFileA("testbitmap.bmp"); if(testbitmap_ok) DeleteFileA("testbitmap.bmp");
} }
static void test_D3DXSaveSurfaceToFileInMemory(IDirect3DDevice9 *device)
{
HRESULT hr;
RECT rect;
ID3DXBuffer *buffer;
IDirect3DSurface9 *surface;
hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL);
if (FAILED(hr)) {
skip("Couldn't create surface\n");
return;
}
SetRect(&rect, 0, 0, 0, 0);
hr = D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_BMP, surface, NULL, &rect);
/* fails with the debug version of d3d9 */
ok(hr == D3D_OK || broken(hr == D3DERR_INVALIDCALL), "D3DXSaveSurfaceToFileInMemory returned %#x, expected %#x\n", hr, D3D_OK);
if (SUCCEEDED(hr)) {
DWORD size = ID3DXBuffer_GetBufferSize(buffer);
ok(size > 0, "ID3DXBuffer_GetBufferSize returned %u, expected > 0\n", size);
ID3DXBuffer_Release(buffer);
}
IDirect3DSurface9_Release(surface);
}
static void test_D3DXSaveSurfaceToFile(IDirect3DDevice9 *device) static void test_D3DXSaveSurfaceToFile(IDirect3DDevice9 *device)
{ {
HRESULT hr; HRESULT hr;
@ -1037,6 +1063,7 @@ START_TEST(surface)
test_D3DXGetImageInfo(); test_D3DXGetImageInfo();
test_D3DXLoadSurface(device); test_D3DXLoadSurface(device);
test_D3DXSaveSurfaceToFileInMemory(device);
test_D3DXSaveSurfaceToFile(device); test_D3DXSaveSurfaceToFile(device);
check_release((IUnknown*)device, 0); check_release((IUnknown*)device, 0);

View File

@ -158,6 +158,25 @@ HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer,
return S_OK; return S_OK;
} }
HRESULT write_buffer_to_file(const WCHAR *dst_filename, ID3DXBuffer *buffer)
{
HRESULT hr = S_OK;
void *buffer_pointer;
DWORD buffer_size;
HANDLE file = CreateFileW(dst_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
buffer_pointer = ID3DXBuffer_GetBufferPointer(buffer);
buffer_size = ID3DXBuffer_GetBufferSize(buffer);
if (!WriteFile(file, buffer_pointer, buffer_size, NULL, NULL))
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(file);
return hr;
}
/************************************************************ /************************************************************
* get_format_info * get_format_info

View File

@ -168,6 +168,12 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface,
D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect,
DWORD filter, D3DCOLOR color_key); DWORD filter, D3DCOLOR color_key);
HRESULT WINAPI D3DXSaveSurfaceToFileInMemory( LPD3DXBUFFER *destbuffer,
D3DXIMAGE_FILEFORMAT destformat,
LPDIRECT3DSURFACE9 srcsurface,
CONST PALETTEENTRY *srcpalette,
CONST RECT *srcrect);
HRESULT WINAPI D3DXSaveSurfaceToFileA( LPCSTR destfile, HRESULT WINAPI D3DXSaveSurfaceToFileA( LPCSTR destfile,
D3DXIMAGE_FILEFORMAT destformat, D3DXIMAGE_FILEFORMAT destformat,
LPDIRECT3DSURFACE9 srcsurface, LPDIRECT3DSURFACE9 srcsurface,