[2/5] d3dx9: Implement D3DXSaveSurfaceToFileInMemory.
Józef Kucia
joseph.kucia at gmail.com
Mon May 28 00:07:22 CDT 2012
Fixes bug 23706.
---
dlls/d3dx9_36/d3dx9_36.spec | 2 +-
dlls/d3dx9_36/d3dx9_36_private.h | 2 +
dlls/d3dx9_36/surface.c | 93 ++++++++++++++++++++++++++++++++-----
dlls/d3dx9_36/tests/surface.c | 27 +++++++++++
dlls/d3dx9_36/util.c | 19 ++++++++
include/d3dx9tex.h | 6 +++
6 files changed, 135 insertions(+), 14 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec
index aa2046a..44efaf5 100644
--- a/dlls/d3dx9_36/d3dx9_36.spec
+++ b/dlls/d3dx9_36/d3dx9_36.spec
@@ -264,7 +264,7 @@
@ stub D3DXSavePRTCompBufferToFileA(ptr ptr)
@ stub D3DXSavePRTCompBufferToFileW(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)
@ stub D3DXSaveTextureToFileA(ptr long ptr ptr)
@ stub D3DXSaveTextureToFileInMemory(ptr long ptr ptr)
diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index be460f2..1cbb7cf 100644
--- a/dlls/d3dx9_36/d3dx9_36_private.h
+++ b/dlls/d3dx9_36/d3dx9_36_private.h
@@ -59,6 +59,8 @@ typedef struct _PixelFormatDesc {
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 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_idx(int idx) DECLSPEC_HIDDEN;
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c
index d490cef..1e0ae02 100644
--- a/dlls/d3dx9_36/surface.c
+++ b/dlls/d3dx9_36/surface.c
@@ -23,6 +23,7 @@
#include "d3dx9_36_private.h"
#include "initguid.h"
+#include "ole2.h"
#include "wincodec.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@@ -1584,6 +1585,7 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO
int len;
WCHAR *filename;
HRESULT hr;
+ ID3DXBuffer *buffer;
TRACE("(%s, %#x, %p, %p, %s): relay\n",
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;
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);
return hr;
@@ -1604,11 +1611,33 @@ HRESULT WINAPI D3DXSaveSurfaceToFileA(const char *dst_filename, D3DXIMAGE_FILEFO
HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
IDirect3DSurface9 *src_surface, const PALETTEENTRY *src_palette, const RECT *src_rect)
{
+ 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)
+{
IWICImagingFactory *factory;
IWICBitmapEncoder *encoder = NULL;
IWICBitmapFrameEncode *frame = NULL;
IPropertyBag2 *encoder_options = NULL;
- IWICStream *stream = NULL;
+ IStream *stream = NULL;
+ IWICStream *wic_stream = NULL;
HRESULT hr;
HRESULT initresult;
const CLSID *encoder_clsid;
@@ -1618,11 +1647,15 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
D3DSURFACE_DESC src_surface_desc;
D3DLOCKED_RECT locked_rect;
int width, height;
+ STATSTG stream_stats;
+ HGLOBAL stream_hglobal;
+ ID3DXBuffer *buffer;
+ DWORD size;
- TRACE("(%s, %#x, %p, %p, %s)\n",
- wine_dbgstr_w(dst_filename), file_format, src_surface, src_palette, wine_dbgstr_rect(src_rect));
+ TRACE("(%p, %#x, %p, %p, %s)\n",
+ 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)
{
@@ -1657,7 +1690,10 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
if (src_rect)
{
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)
return D3DERR_INVALIDCALL;
if (src_rect->left > src_rect->right || src_rect->top > src_rect->bottom)
@@ -1680,20 +1716,25 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
&IID_IWICImagingFactory, (void **)&factory);
if (FAILED(hr)) goto cleanup_err;
- hr = IWICImagingFactory_CreateStream(factory, &stream);
+ hr = IWICImagingFactory_CreateStream(factory, &wic_stream);
IWICImagingFactory_Release(factory);
if (FAILED(hr)) goto cleanup_err;
- hr = IWICStream_InitializeFromFilename(stream, dst_filename, GENERIC_WRITE);
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
if (FAILED(hr)) goto cleanup_err;
+ hr = IWICStream_InitializeFromIStream(wic_stream, stream);
+ if (FAILED(hr))
+ {
+ IStream_Release(stream);
+ goto cleanup_err;
+ }
+
hr = CoCreateInstance(encoder_clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICBitmapEncoder, (void **)&encoder);
if (FAILED(hr)) goto cleanup_err;
- hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)stream, WICBitmapEncoderNoCache);
- IStream_Release((IStream *)stream);
- stream = NULL;
+ hr = IWICBitmapEncoder_Initialize(encoder, (IStream *)wic_stream, WICBitmapEncoderNoCache);
if (FAILED(hr)) goto cleanup_err;
hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame, &encoder_options);
@@ -1783,11 +1824,37 @@ HRESULT WINAPI D3DXSaveSurfaceToFileW(const WCHAR *dst_filename, D3DXIMAGE_FILEF
}
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:
- if (FAILED(hr)) hr = D3DERR_INVALIDCALL;
+ if (FAILED(hr) && hr != E_OUTOFMEMORY)
+ hr = D3DERR_INVALIDCALL;
cleanup:
- if (stream) IStream_Release((IStream *)stream);
+ if (wic_stream) IWICStream_Release(wic_stream);
if (frame) IWICBitmapFrameEncode_Release(frame);
if (encoder_options) IPropertyBag2_Release(encoder_options);
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c
index 2f1f2a8..78ec0ca 100644
--- a/dlls/d3dx9_36/tests/surface.c
+++ b/dlls/d3dx9_36/tests/surface.c
@@ -920,6 +920,32 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
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)
{
HRESULT hr;
@@ -1037,6 +1063,7 @@ START_TEST(surface)
test_D3DXGetImageInfo();
test_D3DXLoadSurface(device);
+ test_D3DXSaveSurfaceToFileInMemory(device);
test_D3DXSaveSurfaceToFile(device);
check_release((IUnknown*)device, 0);
diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c
index d936fb9..cf974cf 100644
--- a/dlls/d3dx9_36/util.c
+++ b/dlls/d3dx9_36/util.c
@@ -158,6 +158,25 @@ HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, LPVOID *buffer,
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
diff --git a/include/d3dx9tex.h b/include/d3dx9tex.h
index 7cfd896..0e89021 100644
--- a/include/d3dx9tex.h
+++ b/include/d3dx9tex.h
@@ -168,6 +168,12 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface,
D3DFORMAT src_format, UINT src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect,
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,
D3DXIMAGE_FILEFORMAT destformat,
LPDIRECT3DSURFACE9 srcsurface,
--
1.7.8.6
More information about the wine-patches
mailing list