From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 32 +++++ dlls/d3dx9_36/surface.c | 231 ++++++++++++++++++++-------------- 2 files changed, 166 insertions(+), 97 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 668fbb27b28..1d4fd2e3125 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -68,6 +68,38 @@ struct pixel_format_desc { void (*to_rgba)(const struct vec4 *src, struct vec4 *dst, const PALETTEENTRY *palette); };
+enum d3dx_resource_type +{ + D3DX_RESOURCE_TYPE_IMAGE = 1, +}; + +struct d3dx_resource; +struct d3dx_resource_ops +{ + void (__stdcall *d3dx_resource_release)(struct d3dx_resource *resource); +}; + +#define d3dx_resource_release(resource) (resource)->resource_ops->d3dx_resource_release(resource) +struct d3dx_resource +{ + const struct d3dx_resource_ops *resource_ops; + enum d3dx_resource_type d3dx_resource_type; + D3DRESOURCETYPE resource_type; + D3DFORMAT format; + + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t mip_levels; +}; + +struct d3dx_image_resource +{ + struct d3dx_resource resource; + + D3DXIMAGE_FILEFORMAT image_file_format; +}; + struct d3dx_include_from_file { ID3DXInclude ID3DXInclude_iface; diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 1420b4d6ebe..c2e81358289 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -24,6 +24,7 @@ #include "initguid.h" #include "ole2.h" #include "wincodec.h" +#include <assert.h>
#include "txc_dxtn.h"
@@ -481,78 +482,6 @@ static UINT calculate_dds_file_size(D3DFORMAT format, UINT width, UINT height, U return file_size; }
-/************************************************************ -* get_image_info_from_dds -* -* Fills a D3DXIMAGE_INFO structure with information -* about a DDS file stored in the memory. -* -* PARAMS -* buffer [I] pointer to DDS data -* length [I] size of DDS data -* info [O] pointer to D3DXIMAGE_INFO structure -* -* RETURNS -* Success: D3D_OK -* Failure: D3DXERR_INVALIDDATA -* -*/ -static HRESULT get_image_info_from_dds(const void *buffer, UINT length, D3DXIMAGE_INFO *info) -{ - UINT faces = 1; - UINT expected_length; - const struct dds_header *header = buffer; - - if (length < sizeof(*header) || !info) - return D3DXERR_INVALIDDATA; - - if (header->pixel_format.size != sizeof(header->pixel_format)) - return D3DXERR_INVALIDDATA; - - info->Width = header->width; - info->Height = header->height; - info->Depth = 1; - info->MipLevels = header->miplevels ? header->miplevels : 1; - - info->Format = dds_pixel_format_to_d3dformat(&header->pixel_format); - if (info->Format == D3DFMT_UNKNOWN) - return D3DXERR_INVALIDDATA; - - TRACE("Pixel format is %#x\n", info->Format); - - if (header->caps2 & DDS_CAPS2_VOLUME) - { - info->Depth = header->depth; - info->ResourceType = D3DRTYPE_VOLUMETEXTURE; - } - else if (header->caps2 & DDS_CAPS2_CUBEMAP) - { - DWORD face; - faces = 0; - for (face = DDS_CAPS2_CUBEMAP_POSITIVEX; face <= DDS_CAPS2_CUBEMAP_NEGATIVEZ; face <<= 1) - { - if (header->caps2 & face) - faces++; - } - info->ResourceType = D3DRTYPE_CUBETEXTURE; - } - else - { - info->ResourceType = D3DRTYPE_TEXTURE; - } - - expected_length = calculate_dds_file_size(info->Format, info->Width, info->Height, info->Depth, - info->MipLevels, faces); - if (length < expected_length) - { - WARN("File is too short %u, expected at least %u bytes\n", length, expected_length); - return D3DXERR_INVALIDDATA; - } - - info->ImageFileFormat = D3DXIFF_DDS; - return D3D_OK; -} - static HRESULT load_surface_from_dds(IDirect3DSurface9 *dst_surface, const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_data, const RECT *src_rect, DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info) @@ -822,6 +751,79 @@ HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, co return D3D_OK; }
+static inline struct d3dx_image_resource *d3dx_image_resource_from_resource(struct d3dx_resource *resource) +{ + assert(resource->d3dx_resource_type == D3DX_RESOURCE_TYPE_IMAGE); + return CONTAINING_RECORD(resource, struct d3dx_image_resource, resource); +} + +static void __stdcall d3dx_image_resource_release(struct d3dx_resource *resource) +{ + struct d3dx_image_resource *image_resource = d3dx_image_resource_from_resource(resource); + + TRACE("image_resource %p.\n", image_resource); + free(image_resource); +} + +static const struct d3dx_resource_ops image_resource_ops = +{ + d3dx_image_resource_release, +}; + +static HRESULT d3dx_initialize_image_resource_from_dds(const void *src_data, uint32_t src_data_size, + struct d3dx_image_resource *image_resource) +{ + struct d3dx_resource *resource = &image_resource->resource; + const struct dds_header *header = src_data; + uint32_t expected_src_data_size; + uint32_t faces = 1; + + if (src_data_size < sizeof(*header) || header->pixel_format.size != sizeof(header->pixel_format)) + return D3DXERR_INVALIDDATA; + + TRACE("File type is DDS.\n"); + resource->width = header->width; + resource->height = header->height; + resource->depth = 1; + resource->mip_levels = header->miplevels ? header->miplevels : 1; + resource->format = dds_pixel_format_to_d3dformat(&header->pixel_format); + + if (resource->format == D3DFMT_UNKNOWN) + return D3DXERR_INVALIDDATA; + + TRACE("Pixel format is %#x.\n", resource->format); + if (header->caps2 & DDS_CAPS2_VOLUME) + { + resource->depth = header->depth; + resource->resource_type = D3DRTYPE_VOLUMETEXTURE; + } + else if (header->caps2 & DDS_CAPS2_CUBEMAP) + { + DWORD face; + + faces = 0; + for (face = DDS_CAPS2_CUBEMAP_POSITIVEX; face <= DDS_CAPS2_CUBEMAP_NEGATIVEZ; face <<= 1) + { + if (header->caps2 & face) + faces++; + } + resource->resource_type = D3DRTYPE_CUBETEXTURE; + } + else + resource->resource_type = D3DRTYPE_TEXTURE; + + expected_src_data_size = calculate_dds_file_size(resource->format, resource->width, resource->height, + resource->depth, resource->mip_levels, faces); + if (src_data_size < expected_src_data_size) + { + WARN("File is too short %u, expected at least %u bytes.\n", src_data_size, expected_src_data_size); + return D3DXERR_INVALIDDATA; + } + + image_resource->image_file_format = D3DXIFF_DDS; + return D3D_OK; +} + static BOOL convert_dib_to_bmp(const void **data, unsigned int *size) { ULONG header_size; @@ -889,28 +891,29 @@ static BOOL convert_dib_to_bmp(const void **data, unsigned int *size)
/* windowscodecs always returns xRGB, but we should return ARGB if and only if * at least one pixel has a non-zero alpha component. */ -static BOOL image_is_argb(IWICBitmapFrameDecode *frame, const D3DXIMAGE_INFO *info) +static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image_resource *image_resource) { + struct d3dx_resource *resource = &image_resource->resource; unsigned int size, i; BYTE *buffer; HRESULT hr;
- if (info->Format != D3DFMT_X8R8G8B8 || (info->ImageFileFormat != D3DXIFF_BMP - && info->ImageFileFormat != D3DXIFF_TGA)) + if (resource->format != D3DFMT_X8R8G8B8 || (image_resource->image_file_format != D3DXIFF_BMP + && image_resource->image_file_format != D3DXIFF_TGA)) return FALSE;
- size = info->Width * info->Height * 4; + size = resource->width * resource->height * 4; if (!(buffer = malloc(size))) return FALSE;
- if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, info->Width * 4, size, buffer))) + if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, resource->width * 4, size, buffer))) { ERR("Failed to copy pixels, hr %#lx.\n", hr); free(buffer); return FALSE; }
- for (i = 0; i < info->Width * info->Height; ++i) + for (i = 0; i < resource->width * resource->height; ++i) { if (buffer[i * 4 + 3]) { @@ -976,8 +979,10 @@ static const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) } }
-static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_size, D3DXIMAGE_INFO *info) +static HRESULT d3dx_initialize_image_resource_from_wic(const void *src_data, uint32_t src_data_size, + struct d3dx_image_resource *image_resource) { + struct d3dx_resource *resource = &image_resource->resource; IWICBitmapFrameDecode *bitmap_frame = NULL; IWICBitmapDecoder *bitmap_decoder = NULL; uint32_t src_image_size = src_data_size; @@ -1020,17 +1025,17 @@ static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_s if (FAILED(hr)) goto exit;
- info->ImageFileFormat = wic_container_guid_to_d3dx_file_format(&container_format); - if (is_dib && info->ImageFileFormat == D3DXIFF_BMP) - info->ImageFileFormat = D3DXIFF_DIB; - else if (info->ImageFileFormat == D3DXIFF_FORCE_DWORD) + image_resource->image_file_format = wic_container_guid_to_d3dx_file_format(&container_format); + if (is_dib && image_resource->image_file_format == D3DXIFF_BMP) + image_resource->image_file_format = D3DXIFF_DIB; + else if (image_resource->image_file_format == D3DXIFF_FORCE_DWORD) { WARN("Unsupported image file format %s.\n", debugstr_guid(&container_format)); hr = D3DXERR_INVALIDDATA; goto exit; }
- TRACE("File type is %s.\n", debug_d3dx_image_file_format(info->ImageFileFormat)); + TRACE("File type is %s.\n", debug_d3dx_image_file_format(image_resource->image_file_format)); hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) { @@ -1042,7 +1047,7 @@ static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_s if (FAILED(hr)) goto exit;
- hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &info->Width, &info->Height); + hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &resource->width, &resource->height); if (FAILED(hr)) goto exit;
@@ -1050,19 +1055,19 @@ static HRESULT get_image_info_from_wic(const void *src_data, uint32_t src_data_s if (FAILED(hr)) goto exit;
- if ((info->Format = wic_guid_to_d3dformat(&pixel_format)) == D3DFMT_UNKNOWN) + if ((resource->format = wic_guid_to_d3dformat(&pixel_format)) == D3DFMT_UNKNOWN) { WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); hr = D3DXERR_INVALIDDATA; goto exit; }
- if (image_is_argb(bitmap_frame, info)) - info->Format = D3DFMT_A8R8G8B8; + if (image_is_argb(bitmap_frame, image_resource)) + resource->format = D3DFMT_A8R8G8B8;
- info->Depth = 1; - info->MipLevels = 1; - info->ResourceType = D3DRTYPE_TEXTURE; + resource->depth = 1; + resource->mip_levels = 1; + resource->resource_type = D3DRTYPE_TEXTURE;
exit: if (is_dib) free((void *)src_image); @@ -1075,6 +1080,33 @@ exit: return hr; }
+static HRESULT d3dx_create_image_resource(const void *src_data, uint32_t src_data_size, + struct d3dx_image_resource **out_resource) +{ + struct d3dx_image_resource *image_resource = NULL; + HRESULT hr; + + if (!src_data || !src_data_size || !out_resource) + return D3DERR_INVALIDCALL; + + *out_resource = NULL; + if (!(image_resource = calloc(1, sizeof(*image_resource)))) + return E_OUTOFMEMORY; + + image_resource->resource.d3dx_resource_type = D3DX_RESOURCE_TYPE_IMAGE; + image_resource->resource.resource_ops = &image_resource_ops; + if ((src_data_size >= 4) && !strncmp(src_data, "DDS ", 4)) + hr = d3dx_initialize_image_resource_from_dds(src_data, src_data_size, image_resource); + else + hr = d3dx_initialize_image_resource_from_wic(src_data, src_data_size, image_resource); + + if (SUCCEEDED(hr)) + *out_resource = image_resource; + + if (FAILED(hr)) d3dx_resource_release(&image_resource->resource); + return hr; +} + /************************************************************ * D3DXGetImageInfoFromFileInMemory * @@ -1098,6 +1130,7 @@ exit: */ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) { + struct d3dx_image_resource *image_resource; HRESULT hr;
TRACE("(%p, %d, %p)\n", data, datasize, info); @@ -1108,17 +1141,21 @@ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, if (!info) return D3D_OK;
- if ((datasize >= 4) && !strncmp(data, "DDS ", 4)) { - TRACE("File type is DDS\n"); - return get_image_info_from_dds(data, datasize, info); - } else - hr = get_image_info_from_wic(data, datasize, info); - + hr = d3dx_create_image_resource(data, datasize, &image_resource); if (FAILED(hr)) { TRACE("Invalid or unsupported image file\n"); return D3DXERR_INVALIDDATA; }
+ info->ImageFileFormat = image_resource->image_file_format; + info->Width = image_resource->resource.width; + info->Height = image_resource->resource.height; + info->Depth = image_resource->resource.depth; + info->MipLevels = image_resource->resource.mip_levels; + info->Format = image_resource->resource.format; + info->ResourceType = image_resource->resource.resource_type; + d3dx_resource_release(&image_resource->resource); + return D3D_OK; }