These are the first steps towards code sharing, finally :)
Patch 4 is a bit big, but it's just copying code from various source files into a single source file. I can attempt to split if if that's preferable for review purposes.
-- v2: d3dx10: Use shared d3dx code in get_image_info when possible. d3dx9: Move functions intended for code sharing into a separate source file. d3dx9: Introduce d3dx_image_file_format enumeration.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index b3f9250e740..ebcd3ffc69d 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1478,7 +1478,7 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz if (FAILED(hr)) goto exit;
- dst_desc = get_format_info(D3DFMT_A8B8G8R8); + dst_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); d3dx_calculate_pixels_size(dst_desc->format, 256, 1, &dst_row_pitch, &dst_slice_pitch); convert_argb_pixels(src_palette, src_row_pitch, src_slice_pitch, &image_map_size, src_desc, (BYTE *)palette, dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, NULL, NULL); @@ -2607,7 +2607,7 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl const PALETTEENTRY *palette) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - const struct pixel_format_desc *ck_format = color_key ? get_format_info(D3DFMT_A8R8G8B8) : NULL; + const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; struct argb_conversion_info conv_info, ck_conv_info; UINT min_width, min_height, min_depth; UINT x, y, z; @@ -2666,7 +2666,7 @@ static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT s const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - const struct pixel_format_desc *ck_format = color_key ? get_format_info(D3DFMT_A8R8G8B8) : NULL; + const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; struct argb_conversion_info conv_info, ck_conv_info; UINT x, y, z;
@@ -2718,19 +2718,19 @@ static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct p switch (desc->format) { case D3DX_PIXEL_FORMAT_DXT1_UNORM: - uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); decompress_bcn_block = bcdec_bc1; break;
case D3DX_PIXEL_FORMAT_DXT2_UNORM: case D3DX_PIXEL_FORMAT_DXT3_UNORM: - uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); decompress_bcn_block = bcdec_bc2; break;
case D3DX_PIXEL_FORMAT_DXT4_UNORM: case D3DX_PIXEL_FORMAT_DXT5_UNORM: - uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); decompress_bcn_block = bcdec_bc3; break;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 13 +++++++++++-- dlls/d3dx9_36/surface.c | 25 ++++++++++++++++--------- dlls/d3dx9_36/texture.c | 4 ++-- dlls/d3dx9_36/util.c | 13 +++++++++++++ 4 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index c8f72562953..d4e317b591e 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -164,6 +164,14 @@ static inline void set_volume_struct(struct volume *volume, uint32_t width, uint volume->depth = depth; }
+enum d3dx_resource_type +{ + D3DX_RESOURCE_TYPE_TEXTURE_2D, + D3DX_RESOURCE_TYPE_TEXTURE_3D, + D3DX_RESOURCE_TYPE_CUBE_TEXTURE, + D3DX_RESOURCE_TYPE_COUNT, +}; + /* These values act as indexes into the pixel_format_desc table. */ enum d3dx_pixel_format_id { @@ -276,7 +284,7 @@ static inline void set_d3dx_pixels(struct d3dx_pixels *pixels, const void *data, #define D3DX_IMAGE_INFO_ONLY 1 struct d3dx_image { - D3DRESOURCETYPE resource_type; + enum d3dx_resource_type resource_type; enum d3dx_pixel_format_id format;
struct volume size; @@ -369,6 +377,7 @@ HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBuffer *buffer);
D3DFORMAT d3dformat_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); enum d3dx_pixel_format_id d3dx_pixel_format_id_from_d3dformat(D3DFORMAT format); +enum d3dx_resource_type d3dx_resource_type_from_d3dresourcetype(D3DRESOURCETYPE type); const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format); const struct pixel_format_desc *get_format_info(D3DFORMAT format); const struct pixel_format_desc *get_format_info_idx(int idx); @@ -383,7 +392,7 @@ HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, IDirect3DSurface9 *temp_surface, BOOL update); uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, uint32_t mip_levels); -HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, +HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels); HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, D3DXIMAGE_FILEFORMAT file_format, ID3DXBuffer **dst_buffer); diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index ebcd3ffc69d..3378c8de1ad 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -423,7 +423,7 @@ uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint return layer_size; }
-HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource_type, +HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels) { HRESULT hr; @@ -454,7 +454,7 @@ HRESULT d3dx_init_dds_header(struct dds_header *header, D3DRESOURCETYPE resource header->miplevels = mip_levels; }
- if (resource_type == D3DRTYPE_CUBETEXTURE) + if (resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) { header->caps |= DDS_CAPS_COMPLEX; header->caps2 |= (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES); @@ -846,7 +846,7 @@ HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct
header = ID3DXBuffer_GetBufferPointer(buffer); pixels = (uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + header_size; - hr = d3dx_init_dds_header(header, D3DRTYPE_TEXTURE, dst_format, &src_pixels->size, 1); + hr = d3dx_init_dds_header(header, D3DX_RESOURCE_TYPE_TEXTURE_2D, dst_format, &src_pixels->size, 1); if (FAILED(hr)) goto exit; if (is_index_format(dst_fmt_desc)) @@ -1026,7 +1026,7 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src if (header->flags & DDS_DEPTH) { image->size.depth = max(header->depth, 1); - image->resource_type = D3DRTYPE_VOLUMETEXTURE; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_3D; } else if (header->caps2 & DDS_CAPS2_CUBEMAP) { @@ -1037,10 +1037,12 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src }
image->layer_count = 6; - image->resource_type = D3DRTYPE_CUBETEXTURE; + image->resource_type = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; } else - image->resource_type = D3DRTYPE_TEXTURE; + { + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + }
image->layer_pitch = d3dx_calculate_layer_pixels_size(image->format, image->size.width, image->size.height, image->size.depth, image->mip_levels); @@ -1366,7 +1368,7 @@ static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src image->size.depth = 1; image->mip_levels = 1; image->layer_count = 1; - image->resource_type = D3DRTYPE_TEXTURE; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D;
exit: if (bitmap_frame) @@ -1607,7 +1609,7 @@ static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src set_volume_struct(&image->size, header->width, header->height, 1); image->mip_levels = 1; image->layer_count = 1; - image->resource_type = D3DRTYPE_TEXTURE; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; image->image_file_format = D3DXIFF_TGA;
if (!(flags & D3DX_IMAGE_INFO_ONLY)) @@ -1755,7 +1757,12 @@ void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *ima info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); break; } - info->ResourceType = image->resource_type; + if (image->resource_type == D3DX_RESOURCE_TYPE_TEXTURE_3D) + info->ResourceType = D3DRTYPE_VOLUMETEXTURE; + else if (image->resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) + info->ResourceType = D3DRTYPE_CUBETEXTURE; + else + info->ResourceType = D3DRTYPE_TEXTURE; }
/************************************************************ diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 9464cae6fa2..2f5d939b036 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1974,8 +1974,8 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE if (FAILED(hr)) return hr;
- hr = d3dx_init_dds_header((struct dds_header *)ID3DXBuffer_GetBufferPointer(buffer), type, fmt_desc->format, &size, - levels); + hr = d3dx_init_dds_header((struct dds_header *)ID3DXBuffer_GetBufferPointer(buffer), + d3dx_resource_type_from_d3dresourcetype(type), fmt_desc->format, &size, levels); if (FAILED(hr)) goto exit;
diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c index c41a8eb7647..0313b209fce 100644 --- a/dlls/d3dx9_36/util.c +++ b/dlls/d3dx9_36/util.c @@ -192,6 +192,19 @@ enum d3dx_pixel_format_id d3dx_pixel_format_id_from_d3dformat(D3DFORMAT format) } }
+enum d3dx_resource_type d3dx_resource_type_from_d3dresourcetype(D3DRESOURCETYPE type) +{ + switch (type) + { + case D3DRTYPE_TEXTURE: return D3DX_RESOURCE_TYPE_TEXTURE_2D; + case D3DRTYPE_VOLUMETEXTURE: return D3DX_RESOURCE_TYPE_TEXTURE_3D; + case D3DRTYPE_CUBETEXTURE: return D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + default: + FIXME("No d3dx_resource_type for D3DRESOURCETYPE %d.\n", type); + return D3DX_RESOURCE_TYPE_COUNT; + } +} + /************************************************************ * map_view_of_file *
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 20 +++++- dlls/d3dx9_36/surface.c | 118 +++++++++++++++++----------------- dlls/d3dx9_36/volume.c | 5 +- 3 files changed, 79 insertions(+), 64 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index d4e317b591e..0eb04d77480 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -164,6 +164,20 @@ static inline void set_volume_struct(struct volume *volume, uint32_t width, uint volume->depth = depth; }
+enum d3dx_image_file_format +{ + D3DX_IMAGE_FILE_FORMAT_BMP = 0, + D3DX_IMAGE_FILE_FORMAT_JPG = 1, + D3DX_IMAGE_FILE_FORMAT_TGA = 2, + D3DX_IMAGE_FILE_FORMAT_PNG = 3, + D3DX_IMAGE_FILE_FORMAT_DDS = 4, + D3DX_IMAGE_FILE_FORMAT_PPM = 5, + D3DX_IMAGE_FILE_FORMAT_DIB = 6, + D3DX_IMAGE_FILE_FORMAT_HDR = 7, + D3DX_IMAGE_FILE_FORMAT_PFM = 8, + D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD = 0x7fffffff +}; + enum d3dx_resource_type { D3DX_RESOURCE_TYPE_TEXTURE_2D, @@ -303,7 +317,7 @@ struct d3dx_image void *image_buf; PALETTEENTRY *image_palette;
- D3DXIMAGE_FILEFORMAT image_file_format; + enum d3dx_image_file_format image_file_format; };
HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, @@ -395,8 +409,8 @@ uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels); HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, - D3DXIMAGE_FILEFORMAT file_format, ID3DXBuffer **dst_buffer); -const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format); + enum d3dx_image_file_format file_format, ID3DXBuffer **dst_buffer); +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format); HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels); diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 3378c8de1ad..b256ae14752 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -468,14 +468,14 @@ HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type return D3D_OK; }
-static const GUID *wic_container_guid_from_d3dx_file_format(D3DXIMAGE_FILEFORMAT iff) +static const GUID *wic_container_guid_from_d3dx_file_format(enum d3dx_image_file_format iff) { switch (iff) { - case D3DXIFF_DIB: - case D3DXIFF_BMP: return &GUID_ContainerFormatBmp; - case D3DXIFF_JPG: return &GUID_ContainerFormatJpeg; - case D3DXIFF_PNG: return &GUID_ContainerFormatPng; + case D3DX_IMAGE_FILE_FORMAT_DIB: + case D3DX_IMAGE_FILE_FORMAT_BMP: return &GUID_ContainerFormatBmp; + case D3DX_IMAGE_FILE_FORMAT_JPG: return &GUID_ContainerFormatJpeg; + case D3DX_IMAGE_FILE_FORMAT_PNG: return &GUID_ContainerFormatPng; default: assert(0 && "Unexpected file format."); return NULL; @@ -483,7 +483,7 @@ static const GUID *wic_container_guid_from_d3dx_file_format(D3DXIMAGE_FILEFORMAT }
static HRESULT d3dx_pixels_save_wic(struct d3dx_pixels *pixels, const struct pixel_format_desc *fmt_desc, - D3DXIMAGE_FILEFORMAT image_file_format, IStream **wic_file, uint32_t *wic_file_size) + enum d3dx_image_file_format image_file_format, IStream **wic_file, uint32_t *wic_file_size) { const GUID *container_format = wic_container_guid_from_d3dx_file_format(image_file_format); const GUID *pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(fmt_desc->format); @@ -526,7 +526,7 @@ static HRESULT d3dx_pixels_save_wic(struct d3dx_pixels *pixels, const struct pix if (FAILED(hr)) goto exit;
- if (image_file_format == D3DXIFF_JPG) + if (image_file_format == D3DX_IMAGE_FILE_FORMAT_JPG) FIXME("JPEG saving quality adjustment currently unimplemented, expect lower quality JPEG.\n");
hr = IWICBitmapFrameEncode_SetSize(wic_frame, pixels->size.width, pixels->size.height); @@ -755,7 +755,7 @@ static enum d3dx_pixel_format_id d3dx_get_closest_d3dx_pixel_format_id(const enu }
HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, - D3DXIMAGE_FILEFORMAT file_format, ID3DXBuffer **dst_buffer) + enum d3dx_image_file_format file_format, ID3DXBuffer **dst_buffer) { enum d3dx_pixel_format_id dst_format = src_fmt_desc->format; const struct pixel_format_desc *dst_fmt_desc; @@ -769,29 +769,29 @@ HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixels = tmp_buf = NULL; switch (file_format) { - case D3DXIFF_DDS: + case D3DX_IMAGE_FILE_FORMAT_DDS: hr = dds_pixel_format_from_d3dx_pixel_format_id(NULL, dst_format); if (FAILED(hr)) return hr; break;
- case D3DXIFF_TGA: + case D3DX_IMAGE_FILE_FORMAT_TGA: dst_format = d3dx_get_closest_d3dx_pixel_format_id(tga_save_pixel_formats, ARRAY_SIZE(tga_save_pixel_formats), dst_format); break;
- case D3DXIFF_PNG: + case D3DX_IMAGE_FILE_FORMAT_PNG: dst_format = d3dx_get_closest_d3dx_pixel_format_id(png_save_pixel_formats, ARRAY_SIZE(png_save_pixel_formats), dst_format); break;
- case D3DXIFF_JPG: + case D3DX_IMAGE_FILE_FORMAT_JPG: dst_format = d3dx_get_closest_d3dx_pixel_format_id(jpg_save_pixel_formats, ARRAY_SIZE(jpg_save_pixel_formats), dst_format); break;
- case D3DXIFF_BMP: - case D3DXIFF_DIB: + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_DIB: { unsigned int i;
@@ -826,7 +826,7 @@ HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct }
dst_fmt_desc = get_d3dx_pixel_format_info(dst_format); - src_pixels->size.depth = (file_format == D3DXIFF_DDS) ? src_pixels->size.depth : 1; + src_pixels->size.depth = (file_format == D3DX_IMAGE_FILE_FORMAT_DDS) ? src_pixels->size.depth : 1; hr = d3dx_calculate_pixels_size(dst_format, src_pixels->size.width, src_pixels->size.height, &dst_row_pitch, &dst_slice_pitch); if (FAILED(hr)) @@ -834,7 +834,7 @@ HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct
switch (file_format) { - case D3DXIFF_DDS: + case D3DX_IMAGE_FILE_FORMAT_DDS: { struct dds_header *header; uint32_t header_size; @@ -855,7 +855,7 @@ HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct break; }
- case D3DXIFF_TGA: + case D3DX_IMAGE_FILE_FORMAT_TGA: { struct tga_header *header;
@@ -877,10 +877,10 @@ HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct break; }
- case D3DXIFF_PNG: - case D3DXIFF_JPG: - case D3DXIFF_BMP: - case D3DXIFF_DIB: + case D3DX_IMAGE_FILE_FORMAT_PNG: + case D3DX_IMAGE_FILE_FORMAT_JPG: + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_DIB: if (src_fmt_desc == dst_fmt_desc) dst_pixels = *src_pixels; else @@ -963,24 +963,24 @@ struct d3dx_file_format_signature { const uint8_t *file_signature; uint32_t file_signature_len; - D3DXIMAGE_FILEFORMAT image_file_format; + enum d3dx_image_file_format image_file_format; };
static const struct d3dx_file_format_signature file_format_signatures[] = { - { bmp_file_signature, sizeof(bmp_file_signature), D3DXIFF_BMP }, - { jpg_file_signature, sizeof(jpg_file_signature), D3DXIFF_JPG }, - { png_file_signature, sizeof(png_file_signature), D3DXIFF_PNG }, - { dds_file_signature, sizeof(dds_file_signature), D3DXIFF_DDS }, - { ppm_plain_file_signature, sizeof(ppm_plain_file_signature), D3DXIFF_PPM }, - { ppm_raw_file_signature, sizeof(ppm_raw_file_signature), D3DXIFF_PPM }, - { hdr_file_signature, sizeof(hdr_file_signature), D3DXIFF_HDR }, - { pfm_color_file_signature, sizeof(pfm_color_file_signature), D3DXIFF_PFM }, - { pfm_gray_file_signature, sizeof(pfm_gray_file_signature), D3DXIFF_PFM }, + { bmp_file_signature, sizeof(bmp_file_signature), D3DX_IMAGE_FILE_FORMAT_BMP }, + { jpg_file_signature, sizeof(jpg_file_signature), D3DX_IMAGE_FILE_FORMAT_JPG }, + { png_file_signature, sizeof(png_file_signature), D3DX_IMAGE_FILE_FORMAT_PNG }, + { dds_file_signature, sizeof(dds_file_signature), D3DX_IMAGE_FILE_FORMAT_DDS }, + { ppm_plain_file_signature, sizeof(ppm_plain_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, + { ppm_raw_file_signature, sizeof(ppm_raw_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, + { hdr_file_signature, sizeof(hdr_file_signature), D3DX_IMAGE_FILE_FORMAT_HDR }, + { pfm_color_file_signature, sizeof(pfm_color_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, + { pfm_gray_file_signature, sizeof(pfm_gray_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, };
static BOOL d3dx_get_image_file_format_from_file_signature(const void *src_data, uint32_t src_data_size, - D3DXIMAGE_FILEFORMAT *out_iff) + enum d3dx_image_file_format *out_iff) { unsigned int i;
@@ -1057,7 +1057,7 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src
image->palette = (is_indexed_fmt) ? (PALETTEENTRY *)(((uint8_t *)src_data) + sizeof(*header)) : NULL; image->pixels = ((BYTE *)src_data) + header_size; - image->image_file_format = D3DXIFF_DDS; + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DDS; if (starting_mip_level && (image->mip_levels > 1)) { uint32_t i, row_pitch, slice_pitch, initial_mip_levels; @@ -1157,7 +1157,7 @@ static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image BYTE *buffer; HRESULT hr;
- if (image->format != D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM || image->image_file_format != D3DXIFF_BMP) + if (image->format != D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM || image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) return FALSE;
size = image->size.width * image->size.height * 4; @@ -1184,20 +1184,20 @@ static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image return FALSE; }
-const char *debug_d3dx_image_file_format(D3DXIMAGE_FILEFORMAT format) +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format) { switch (format) { #define FMT_TO_STR(format) case format: return #format - FMT_TO_STR(D3DXIFF_BMP); - FMT_TO_STR(D3DXIFF_JPG); - FMT_TO_STR(D3DXIFF_TGA); - FMT_TO_STR(D3DXIFF_PNG); - FMT_TO_STR(D3DXIFF_DDS); - FMT_TO_STR(D3DXIFF_PPM); - FMT_TO_STR(D3DXIFF_DIB); - FMT_TO_STR(D3DXIFF_HDR); - FMT_TO_STR(D3DXIFF_PFM); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_BMP); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_JPG); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_TGA); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PNG); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DDS); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PPM); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DIB); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_HDR); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PFM); #undef FMT_TO_STR default: return "unrecognized"; @@ -1287,7 +1287,7 @@ exit: }
static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image, D3DXIMAGE_FILEFORMAT d3dx_file_format, uint32_t flags) + struct d3dx_image *image, enum d3dx_image_file_format d3dx_file_format, uint32_t flags) { const GUID *container_format_guid = wic_container_guid_from_d3dx_file_format(d3dx_file_format); IWICBitmapFrameDecode *bitmap_frame = NULL; @@ -1342,7 +1342,7 @@ static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src switch (image->format) { case D3DX_PIXEL_FORMAT_P2_UINT: - if (image->image_file_format != D3DXIFF_BMP) + if (image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) break; /* Fall through. */
@@ -1610,7 +1610,7 @@ static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src image->mip_levels = 1; image->layer_count = 1; image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; - image->image_file_format = D3DXIFF_TGA; + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_TGA;
if (!(flags & D3DX_IMAGE_INFO_ONLY)) return d3dx_image_tga_decode(src_data, src_data_size, expected_header_size, image); @@ -1621,7 +1621,7 @@ static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, uint32_t starting_mip_level, uint32_t flags) { - D3DXIMAGE_FILEFORMAT iff = D3DXIFF_FORCE_DWORD; + enum d3dx_image_file_format iff = D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD; HRESULT hr;
if (!src_data || !src_data_size || !image) @@ -1638,7 +1638,7 @@ HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3d hr = d3dx_image_init(src_image, src_image_size, image, starting_mip_level, flags); free((void *)src_image); if (SUCCEEDED(hr)) - image->image_file_format = D3DXIFF_DIB; + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DIB; return hr; }
@@ -1648,24 +1648,24 @@ HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3d
switch (iff) { - case D3DXIFF_BMP: - case D3DXIFF_JPG: - case D3DXIFF_PNG: + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_JPG: + case D3DX_IMAGE_FILE_FORMAT_PNG: hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, iff, flags); break;
- case D3DXIFF_DDS: + case D3DX_IMAGE_FILE_FORMAT_DDS: hr = d3dx_initialize_image_from_dds(src_data, src_data_size, image, starting_mip_level); break;
- case D3DXIFF_PPM: - case D3DXIFF_HDR: - case D3DXIFF_PFM: + case D3DX_IMAGE_FILE_FORMAT_PPM: + case D3DX_IMAGE_FILE_FORMAT_HDR: + case D3DX_IMAGE_FILE_FORMAT_PFM: WARN("Unsupported file format %s.\n", debug_d3dx_image_file_format(iff)); hr = E_NOTIMPL; break;
- case D3DXIFF_FORCE_DWORD: + case D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD: ERR("Unrecognized file format.\n"); hr = D3DXERR_INVALIDDATA; break; @@ -1729,7 +1729,7 @@ HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t
void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) { - info->ImageFileFormat = image->image_file_format; + info->ImageFileFormat = (D3DXIMAGE_FILEFORMAT)image->image_file_format; info->Width = image->size.width; info->Height = image->size.height; info->Depth = image->size.depth; @@ -3606,7 +3606,7 @@ HRESULT WINAPI D3DXSaveSurfaceToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE return hr; }
- hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, file_format, &buffer); + hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, (enum d3dx_image_file_format)file_format, &buffer); if (FAILED(hr)) { unlock_surface(src_surface, NULL, temp_surface, FALSE); diff --git a/dlls/d3dx9_36/volume.c b/dlls/d3dx9_36/volume.c index 546959b017e..af89bba5b3c 100644 --- a/dlls/d3dx9_36/volume.c +++ b/dlls/d3dx9_36/volume.c @@ -303,7 +303,8 @@ HRESULT WINAPI D3DXSaveVolumeToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_ case D3DXIFF_HDR: case D3DXIFF_PFM: case D3DXIFF_PPM: - FIXME("File format %s is not supported yet.\n", debug_d3dx_image_file_format(file_format)); + FIXME("File format %s is not supported yet.\n", + debug_d3dx_image_file_format((enum d3dx_image_file_format)file_format)); return E_NOTIMPL;
default: @@ -350,7 +351,7 @@ HRESULT WINAPI D3DXSaveVolumeToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE_ return hr; }
- hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, file_format, &buffer); + hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, (enum d3dx_image_file_format)file_format, &buffer); IDirect3DVolume9_UnlockBox(src_volume); if (SUCCEEDED(hr)) *dst_buffer = buffer;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_24/Makefile.in | 3 +- dlls/d3dx9_25/Makefile.in | 3 +- dlls/d3dx9_26/Makefile.in | 3 +- dlls/d3dx9_27/Makefile.in | 3 +- dlls/d3dx9_28/Makefile.in | 3 +- dlls/d3dx9_29/Makefile.in | 3 +- dlls/d3dx9_30/Makefile.in | 3 +- dlls/d3dx9_31/Makefile.in | 3 +- dlls/d3dx9_32/Makefile.in | 3 +- dlls/d3dx9_33/Makefile.in | 3 +- dlls/d3dx9_34/Makefile.in | 3 +- dlls/d3dx9_35/Makefile.in | 3 +- dlls/d3dx9_36/Makefile.in | 3 +- dlls/d3dx9_36/d3dx9_private.h | 350 +--- dlls/d3dx9_36/d3dx_helpers.c | 2907 ++++++++++++++++++++++++++++ dlls/d3dx9_36/d3dx_helpers.h | 384 ++++ dlls/d3dx9_36/math.c | 105 -- dlls/d3dx9_36/surface.c | 3359 ++++----------------------------- dlls/d3dx9_36/util.c | 70 +- dlls/d3dx9_37/Makefile.in | 3 +- dlls/d3dx9_38/Makefile.in | 3 +- dlls/d3dx9_39/Makefile.in | 3 +- dlls/d3dx9_40/Makefile.in | 3 +- dlls/d3dx9_41/Makefile.in | 3 +- dlls/d3dx9_42/Makefile.in | 3 +- dlls/d3dx9_43/Makefile.in | 3 +- 26 files changed, 3656 insertions(+), 3579 deletions(-) create mode 100644 dlls/d3dx9_36/d3dx_helpers.c create mode 100644 dlls/d3dx9_36/d3dx_helpers.h
diff --git a/dlls/d3dx9_24/Makefile.in b/dlls/d3dx9_24/Makefile.in index e5329f14ab0..9dc4a118c2d 100644 --- a/dlls/d3dx9_24/Makefile.in +++ b/dlls/d3dx9_24/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=24 +EXTRADEFS = -DD3DX_SDK_VERSION=24 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_24.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_25/Makefile.in b/dlls/d3dx9_25/Makefile.in index 5ee141cddca..7c583a300a7 100644 --- a/dlls/d3dx9_25/Makefile.in +++ b/dlls/d3dx9_25/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=25 +EXTRADEFS = -DD3DX_SDK_VERSION=25 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_25.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_26/Makefile.in b/dlls/d3dx9_26/Makefile.in index 5ca36cfbd55..35ac1cc1a62 100644 --- a/dlls/d3dx9_26/Makefile.in +++ b/dlls/d3dx9_26/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=26 +EXTRADEFS = -DD3DX_SDK_VERSION=26 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_26.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_27/Makefile.in b/dlls/d3dx9_27/Makefile.in index 09172cf7e94..0f68cf5eed7 100644 --- a/dlls/d3dx9_27/Makefile.in +++ b/dlls/d3dx9_27/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=27 +EXTRADEFS = -DD3DX_SDK_VERSION=27 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_27.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_28/Makefile.in b/dlls/d3dx9_28/Makefile.in index 3cd59749900..5158a630ba2 100644 --- a/dlls/d3dx9_28/Makefile.in +++ b/dlls/d3dx9_28/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=28 +EXTRADEFS = -DD3DX_SDK_VERSION=28 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_28.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_29/Makefile.in b/dlls/d3dx9_29/Makefile.in index c7a5b1aacc9..25d345f0f55 100644 --- a/dlls/d3dx9_29/Makefile.in +++ b/dlls/d3dx9_29/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=29 +EXTRADEFS = -DD3DX_SDK_VERSION=29 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_29.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_30/Makefile.in b/dlls/d3dx9_30/Makefile.in index 2c618fd1113..309ed79e6ab 100644 --- a/dlls/d3dx9_30/Makefile.in +++ b/dlls/d3dx9_30/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=30 +EXTRADEFS = -DD3DX_SDK_VERSION=30 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_30.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_31/Makefile.in b/dlls/d3dx9_31/Makefile.in index 7f41c5cf369..3c1d1dfdf46 100644 --- a/dlls/d3dx9_31/Makefile.in +++ b/dlls/d3dx9_31/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=31 +EXTRADEFS = -DD3DX_SDK_VERSION=31 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_31.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_32/Makefile.in b/dlls/d3dx9_32/Makefile.in index 2bdc91c4c0f..2e0a4c3632d 100644 --- a/dlls/d3dx9_32/Makefile.in +++ b/dlls/d3dx9_32/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=32 +EXTRADEFS = -DD3DX_SDK_VERSION=32 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_32.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_33/Makefile.in b/dlls/d3dx9_33/Makefile.in index 9b4e7671c21..4be9ead8a15 100644 --- a/dlls/d3dx9_33/Makefile.in +++ b/dlls/d3dx9_33/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=33 +EXTRADEFS = -DD3DX_SDK_VERSION=33 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_33.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_34/Makefile.in b/dlls/d3dx9_34/Makefile.in index 446454e6bae..e50ac880259 100644 --- a/dlls/d3dx9_34/Makefile.in +++ b/dlls/d3dx9_34/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=34 +EXTRADEFS = -DD3DX_SDK_VERSION=34 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_34.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_35/Makefile.in b/dlls/d3dx9_35/Makefile.in index bc90efda4ef..00a1d31bac5 100644 --- a/dlls/d3dx9_35/Makefile.in +++ b/dlls/d3dx9_35/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=35 +EXTRADEFS = -DD3DX_SDK_VERSION=35 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_35.dll IMPORTLIB = d3dx9_35 IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d @@ -10,6 +10,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_36/Makefile.in b/dlls/d3dx9_36/Makefile.in index a0100daf666..e9dceecf3b6 100644 --- a/dlls/d3dx9_36/Makefile.in +++ b/dlls/d3dx9_36/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=36 +EXTRADEFS = -DD3DX_SDK_VERSION=36 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_36.dll IMPORTLIB = d3dx9 IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 0eb04d77480..977b69a815f 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -26,8 +26,7 @@ #include "wine/debug.h" #include "wine/rbtree.h"
-#define COBJMACROS -#include "d3dx9.h" +#include "d3dx_helpers.h"
#define ULONG64_MAX (~(ULONG64)0)
@@ -50,281 +49,6 @@ static inline HRESULT d3dx9_handle_load_filter(DWORD *filter) return d3dx9_validate_filter(*filter); }
-#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) - -/* dds_header.flags */ -#define DDS_CAPS 0x1 -#define DDS_HEIGHT 0x2 -#define DDS_WIDTH 0x4 -#define DDS_PITCH 0x8 -#define DDS_PIXELFORMAT 0x1000 -#define DDS_MIPMAPCOUNT 0x20000 -#define DDS_LINEARSIZE 0x80000 -#define DDS_DEPTH 0x800000 - -/* dds_header.caps */ -#define DDSCAPS_ALPHA 0x2 -#define DDS_CAPS_COMPLEX 0x8 -#define DDSCAPS_PALETTE 0x100 -#define DDS_CAPS_TEXTURE 0x1000 -#define DDS_CAPS_MIPMAP 0x400000 - -/* dds_header.caps2 */ -#define DDS_CAPS2_CUBEMAP 0x200 -#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 -#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 -#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 -#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 -#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 -#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 -#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ - | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ - | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) -#define DDS_CAPS2_VOLUME 0x200000 - -/* dds_pixel_format.flags */ -#define DDS_PF_ALPHA 0x1 -#define DDS_PF_ALPHA_ONLY 0x2 -#define DDS_PF_FOURCC 0x4 -#define DDS_PF_INDEXED 0x20 -#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 -{ - DWORD size; - DWORD flags; - DWORD fourcc; - DWORD bpp; - DWORD rmask; - DWORD gmask; - DWORD bmask; - DWORD amask; -}; - -struct dds_header -{ - DWORD signature; - DWORD size; - DWORD flags; - DWORD height; - DWORD width; - DWORD pitch_or_linear_size; - DWORD depth; - DWORD miplevels; - DWORD reserved[11]; - struct dds_pixel_format pixel_format; - DWORD caps; - DWORD caps2; - DWORD caps3; - DWORD caps4; - DWORD reserved2; -}; - -struct vec4 -{ - float x, y, z, w; -}; - -enum range { - RANGE_FULL = 0, - RANGE_UNORM = 1, - RANGE_SNORM = 2, -}; - -struct d3dx_color -{ - struct vec4 value; - enum range rgb_range; - enum range a_range; -}; - -static inline void set_d3dx_color(struct d3dx_color *color, const struct vec4 *value, enum range rgb_range, - enum range a_range) -{ - color->value = *value; - color->rgb_range = rgb_range; - color->a_range = a_range; -} - -struct volume -{ - UINT width; - UINT height; - UINT depth; -}; - -static inline void set_volume_struct(struct volume *volume, uint32_t width, uint32_t height, uint32_t depth) -{ - volume->width = width; - volume->height = height; - volume->depth = depth; -} - -enum d3dx_image_file_format -{ - D3DX_IMAGE_FILE_FORMAT_BMP = 0, - D3DX_IMAGE_FILE_FORMAT_JPG = 1, - D3DX_IMAGE_FILE_FORMAT_TGA = 2, - D3DX_IMAGE_FILE_FORMAT_PNG = 3, - D3DX_IMAGE_FILE_FORMAT_DDS = 4, - D3DX_IMAGE_FILE_FORMAT_PPM = 5, - D3DX_IMAGE_FILE_FORMAT_DIB = 6, - D3DX_IMAGE_FILE_FORMAT_HDR = 7, - D3DX_IMAGE_FILE_FORMAT_PFM = 8, - D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD = 0x7fffffff -}; - -enum d3dx_resource_type -{ - D3DX_RESOURCE_TYPE_TEXTURE_2D, - D3DX_RESOURCE_TYPE_TEXTURE_3D, - D3DX_RESOURCE_TYPE_CUBE_TEXTURE, - D3DX_RESOURCE_TYPE_COUNT, -}; - -/* These values act as indexes into the pixel_format_desc table. */ -enum d3dx_pixel_format_id -{ - D3DX_PIXEL_FORMAT_B8G8R8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, - D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, - D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, - D3DX_PIXEL_FORMAT_B5G6R5_UNORM, - D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, - D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, - D3DX_PIXEL_FORMAT_B2G3R3_UNORM, - D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, - D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, - D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, - D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, - D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, - D3DX_PIXEL_FORMAT_R16G16B16_UNORM, - D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, - D3DX_PIXEL_FORMAT_R16G16_UNORM, - D3DX_PIXEL_FORMAT_A8_UNORM, - D3DX_PIXEL_FORMAT_L8A8_UNORM, - D3DX_PIXEL_FORMAT_L4A4_UNORM, - D3DX_PIXEL_FORMAT_L8_UNORM, - D3DX_PIXEL_FORMAT_L16_UNORM, - D3DX_PIXEL_FORMAT_DXT1_UNORM, - D3DX_PIXEL_FORMAT_DXT2_UNORM, - D3DX_PIXEL_FORMAT_DXT3_UNORM, - D3DX_PIXEL_FORMAT_DXT4_UNORM, - D3DX_PIXEL_FORMAT_DXT5_UNORM, - D3DX_PIXEL_FORMAT_R16_FLOAT, - D3DX_PIXEL_FORMAT_R16G16_FLOAT, - D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, - D3DX_PIXEL_FORMAT_R32_FLOAT, - D3DX_PIXEL_FORMAT_R32G32_FLOAT, - D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, - D3DX_PIXEL_FORMAT_P1_UINT, - D3DX_PIXEL_FORMAT_P2_UINT, - D3DX_PIXEL_FORMAT_P4_UINT, - D3DX_PIXEL_FORMAT_P8_UINT, - D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, - D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, - D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, - D3DX_PIXEL_FORMAT_U8V8_SNORM, - D3DX_PIXEL_FORMAT_U16V16_SNORM, - D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, - D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, - D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, - D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, - D3DX_PIXEL_FORMAT_UYVY, - D3DX_PIXEL_FORMAT_YUY2, - D3DX_PIXEL_FORMAT_COUNT, -}; - -/* for internal use */ -enum component_type -{ - CTYPE_EMPTY, - CTYPE_UNORM, - CTYPE_SNORM, - CTYPE_FLOAT, - CTYPE_LUMA, - CTYPE_INDEX, -}; - -enum format_flag -{ - FMT_FLAG_DXT = 0x01, - FMT_FLAG_PACKED = 0x02, - /* Internal only format, has no exact D3DFORMAT equivalent. */ - FMT_FLAG_INTERNAL = 0x04, -}; - -struct pixel_format_desc { - enum d3dx_pixel_format_id format; - BYTE bits[4]; - BYTE shift[4]; - UINT bytes_per_pixel; - UINT block_width; - UINT block_height; - UINT block_byte_count; - enum component_type a_type; - enum component_type rgb_type; - uint32_t flags; -}; - -struct d3dx_pixels -{ - const void *data; - uint32_t row_pitch; - uint32_t slice_pitch; - const PALETTEENTRY *palette; - - struct volume size; - RECT unaligned_rect; -}; - -static inline void set_d3dx_pixels(struct d3dx_pixels *pixels, const void *data, uint32_t row_pitch, - uint32_t slice_pitch, const PALETTEENTRY *palette, uint32_t width, uint32_t height, uint32_t depth, - const RECT *unaligned_rect) -{ - pixels->data = data; - pixels->row_pitch = row_pitch; - pixels->slice_pitch = slice_pitch; - pixels->palette = palette; - set_volume_struct(&pixels->size, width, height, depth); - pixels->unaligned_rect = *unaligned_rect; -} - -#define D3DX_IMAGE_INFO_ONLY 1 -struct d3dx_image -{ - enum d3dx_resource_type resource_type; - enum d3dx_pixel_format_id format; - - struct volume size; - uint32_t mip_levels; - uint32_t layer_count; - - BYTE *pixels; - PALETTEENTRY *palette; - uint32_t layer_pitch; - - /* - * image_buf and image_palette are pointers to allocated memory used to store - * image data. If they are non-NULL, they need to be freed when no longer - * in use. - */ - void *image_buf; - PALETTEENTRY *image_palette; - - enum d3dx_image_file_format image_file_format; -}; - -HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, - uint32_t starting_mip_level, uint32_t flags); -void d3dx_image_cleanup(struct d3dx_image *image); -HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, - struct d3dx_pixels *pixels); void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image);
struct d3dx_include_from_file @@ -335,55 +59,6 @@ struct d3dx_include_from_file extern CRITICAL_SECTION from_file_mutex; extern const struct ID3DXIncludeVtbl d3dx_include_from_file_vtbl;
-static inline BOOL is_unknown_format(const struct pixel_format_desc *format) -{ - return (format->format == D3DX_PIXEL_FORMAT_COUNT); -} - -static inline BOOL is_index_format(const struct pixel_format_desc *format) -{ - return (format->a_type == CTYPE_INDEX || format->rgb_type == CTYPE_INDEX); -} - -static inline BOOL is_compressed_format(const struct pixel_format_desc *format) -{ - return !!(format->flags & FMT_FLAG_DXT); -} - -static inline BOOL is_packed_format(const struct pixel_format_desc *format) -{ - return !!(format->flags & FMT_FLAG_PACKED); -} - -static inline BOOL format_types_match(const struct pixel_format_desc *src, const struct pixel_format_desc *dst) -{ - if ((src->a_type && dst->a_type) && (src->a_type != dst->a_type)) - return FALSE; - - if ((src->rgb_type && dst->rgb_type) && (src->rgb_type != dst->rgb_type)) - return FALSE; - - if (src->flags != dst->flags) - return FALSE; - - return (src->rgb_type == dst->rgb_type || src->a_type == dst->a_type); -} - -static inline BOOL is_internal_format(const struct pixel_format_desc *format) -{ - return !!(format->flags & FMT_FLAG_INTERNAL); -} - -static inline BOOL is_conversion_from_supported(const struct pixel_format_desc *format) -{ - return !is_packed_format(format) && !is_unknown_format(format); -} - -static inline BOOL is_conversion_to_supported(const struct pixel_format_desc *format) -{ - return !is_index_format(format) && !is_packed_format(format) && !is_unknown_format(format); -} - HRESULT map_view_of_file(const WCHAR *filename, void **buffer, DWORD *length); HRESULT load_resource_into_memory(HMODULE module, HRSRC resinfo, void **buffer, DWORD *length);
@@ -392,36 +67,13 @@ HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBuffer *buffer); D3DFORMAT d3dformat_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format); enum d3dx_pixel_format_id d3dx_pixel_format_id_from_d3dformat(D3DFORMAT format); enum d3dx_resource_type d3dx_resource_type_from_d3dresourcetype(D3DRESOURCETYPE type); -const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format); const struct pixel_format_desc *get_format_info(D3DFORMAT format); const struct pixel_format_desc *get_format_info_idx(int idx);
-void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, - struct d3dx_color *dst); -void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst); - HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLOCKED_RECT *lock, IDirect3DSurface9 **temp_surface, BOOL write); HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, IDirect3DSurface9 *temp_surface, BOOL update); -uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, - uint32_t depth, uint32_t mip_levels); -HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, - enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels); -HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, - enum d3dx_image_file_format file_format, ID3DXBuffer **dst_buffer); -const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format); -HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, - const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, - uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels); -HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, - const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, - const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key); -void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, - const struct pixel_format_desc *fmt_desc, RECT *aligned_rect); - -unsigned short float_32_to_16(const float in); -float float_16_to_32(const unsigned short in);
/* debug helpers */ const char *debug_d3dxparameter_class(D3DXPARAMETER_CLASS c); diff --git a/dlls/d3dx9_36/d3dx_helpers.c b/dlls/d3dx9_36/d3dx_helpers.c new file mode 100644 index 00000000000..d633ec4e18e --- /dev/null +++ b/dlls/d3dx9_36/d3dx_helpers.c @@ -0,0 +1,2907 @@ +/* + * Copyright 2025 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "wine/debug.h" +#include "d3dx_helpers.h" + +#include "initguid.h" +#include "ole2.h" +#include "wincodec.h" + +#define BCDEC_IMPLEMENTATION +#define BCDEC_STATIC +#include "bcdec.h" +#define STB_DXT_IMPLEMENTATION +#define STB_DXT_STATIC +#include "stb_dxt.h" +#include <assert.h> + +WINE_DEFAULT_DEBUG_CHANNEL(d3dx); + +HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); + +/************************************************************ + * pixel format table providing info about number of bytes per pixel, + * number of bits per channel and format type. + * + * Call get_format_info to request information about a specific format. + */ +static const struct pixel_format_desc formats[] = +{ + /* format bpc shifts bpp blocks alpha type rgb type flags */ + {D3DX_PIXEL_FORMAT_B8G8R8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 3, 1, 1, 3, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, { 8, 8, 8, 8}, {24, 16, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, { 0, 8, 8, 8}, { 0, 0, 8, 16}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B5G6R5_UNORM, { 0, 5, 6, 5}, { 0, 11, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, { 0, 5, 5, 5}, { 0, 10, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, { 1, 5, 5, 5}, {15, 10, 5, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B2G3R3_UNORM, { 0, 3, 3, 2}, { 0, 5, 2, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, { 8, 3, 3, 2}, { 8, 5, 2, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, { 4, 4, 4, 4}, {12, 8, 4, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, { 0, 4, 4, 4}, { 0, 8, 4, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, { 2, 10, 10, 10}, {30, 20, 10, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R16G16B16_UNORM, { 0, 16, 16, 16}, { 0, 0, 16, 32}, 6, 1, 1, 6, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_INTERNAL}, + {D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_UNORM, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_R16G16_UNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, + {D3DX_PIXEL_FORMAT_A8_UNORM, { 8, 0, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_EMPTY, 0 }, + {D3DX_PIXEL_FORMAT_L8A8_UNORM, { 8, 8, 0, 0}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_L4A4_UNORM, { 4, 4, 0, 0}, { 4, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_L8_UNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_L16_UNORM, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_LUMA, 0 }, + {D3DX_PIXEL_FORMAT_DXT1_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_DXT2_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_DXT3_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_DXT4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_DXT5_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_R16_FLOAT, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R16G16_FLOAT, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R32_FLOAT, { 0, 32, 0, 0}, { 0, 0, 0, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R32G32_FLOAT, { 0, 32, 32, 0}, { 0, 0, 32, 0}, 8, 1, 1, 8, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, {32, 32, 32, 32}, {96, 0, 32, 64}, 16, 1, 1, 16, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, + {D3DX_PIXEL_FORMAT_P1_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 8, 1, 1, CTYPE_INDEX, CTYPE_INDEX, FMT_FLAG_INTERNAL}, + {D3DX_PIXEL_FORMAT_P2_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 4, 1, 1, CTYPE_INDEX, CTYPE_INDEX, FMT_FLAG_INTERNAL}, + {D3DX_PIXEL_FORMAT_P4_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 2, 1, 1, CTYPE_INDEX, CTYPE_INDEX, FMT_FLAG_INTERNAL}, + {D3DX_PIXEL_FORMAT_P8_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_INDEX, CTYPE_INDEX, 0 }, + {D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, { 8, 8, 8, 8}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_INDEX, 0 }, + {D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_SNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_SNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U8V8_SNORM, { 0, 8, 8, 0}, { 0, 0, 8, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U16V16_SNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, { 8, 8, 8, 0}, {16, 0, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, + {D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + {D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + {D3DX_PIXEL_FORMAT_UYVY, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + {D3DX_PIXEL_FORMAT_YUY2, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, + /* marks last element */ + {D3DX_PIXEL_FORMAT_COUNT, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 0, 1, 1, 0, CTYPE_EMPTY, CTYPE_EMPTY, 0 }, +}; + +const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format) +{ + return &formats[min(format, D3DX_PIXEL_FORMAT_COUNT)]; +} + +static const struct +{ + const GUID *wic_guid; + enum d3dx_pixel_format_id d3dx_pixel_format; +} wic_pixel_formats[] = +{ + { &GUID_WICPixelFormat8bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, + { &GUID_WICPixelFormat1bppIndexed, D3DX_PIXEL_FORMAT_P1_UINT }, + { &GUID_WICPixelFormat2bppIndexed, D3DX_PIXEL_FORMAT_P2_UINT }, + { &GUID_WICPixelFormat4bppIndexed, D3DX_PIXEL_FORMAT_P4_UINT }, + { &GUID_WICPixelFormat8bppGray, D3DX_PIXEL_FORMAT_L8_UNORM }, + { &GUID_WICPixelFormat16bppBGR555, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, + { &GUID_WICPixelFormat16bppBGR565, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, + { &GUID_WICPixelFormat24bppBGR, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, + { &GUID_WICPixelFormat32bppBGR, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, + { &GUID_WICPixelFormat32bppBGRA, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, + { &GUID_WICPixelFormat48bppRGB, D3DX_PIXEL_FORMAT_R16G16B16_UNORM }, + { &GUID_WICPixelFormat64bppRGBA, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, +}; + +static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_wic_pixel_format(const GUID *guid) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) + { + if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid)) + return wic_pixel_formats[i].d3dx_pixel_format; + } + + return D3DX_PIXEL_FORMAT_COUNT; + +} + +static const GUID *wic_guid_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id d3dx_pixel_format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) + { + if (wic_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) + return wic_pixel_formats[i].wic_guid; + } + + return NULL; +} + +#define TGA_IMAGETYPE_COLORMAPPED 1 +#define TGA_IMAGETYPE_TRUECOLOR 2 +#define TGA_IMAGETYPE_GRAYSCALE 3 +#define TGA_IMAGETYPE_MASK 0x07 +#define TGA_IMAGETYPE_RLE 8 + +#define TGA_IMAGE_RIGHTTOLEFT 0x10 +#define TGA_IMAGE_TOPTOBOTTOM 0x20 + +#pragma pack(push,1) +struct tga_header +{ + uint8_t id_length; + uint8_t color_map_type; + uint8_t image_type; + uint16_t color_map_firstentry; + uint16_t color_map_length; + uint8_t color_map_entrysize; + uint16_t xorigin; + uint16_t yorigin; + uint16_t width; + uint16_t height; + uint8_t depth; + uint8_t image_descriptor; +}; +#pragma pack(pop) + +static const struct +{ + struct dds_pixel_format dds_pixel_format; + enum d3dx_pixel_format_id d3dx_pixel_format; +} dds_pixel_formats[] = +{ + /* DDS_PF_FOURCC. */ + { { 32, DDS_PF_FOURCC, MAKEFOURCC('U','Y','V','Y') }, D3DX_PIXEL_FORMAT_UYVY }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('Y','U','Y','2') }, D3DX_PIXEL_FORMAT_YUY2 }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G') }, D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B') }, D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1') }, D3DX_PIXEL_FORMAT_DXT1_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','2') }, D3DX_PIXEL_FORMAT_DXT2_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3') }, D3DX_PIXEL_FORMAT_DXT3_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','4') }, D3DX_PIXEL_FORMAT_DXT4_UNORM }, + { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5') }, D3DX_PIXEL_FORMAT_DXT5_UNORM }, + /* These aren't actually fourcc values, they're just D3DFMT values. */ + { { 32, DDS_PF_FOURCC, 0x24 }, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, + { { 32, DDS_PF_FOURCC, 0x6e }, D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM }, + { { 32, DDS_PF_FOURCC, 0x6f }, D3DX_PIXEL_FORMAT_R16_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x70 }, D3DX_PIXEL_FORMAT_R16G16_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x71 }, D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x72 }, D3DX_PIXEL_FORMAT_R32_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x73 }, D3DX_PIXEL_FORMAT_R32G32_FLOAT }, + { { 32, DDS_PF_FOURCC, 0x74 }, D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT }, + /* DDS_PF_RGB. */ + { { 32, DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 }, D3DX_PIXEL_FORMAT_B2G3R3_UNORM }, + { { 32, DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, + { { 32, DDS_PF_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, + { { 32, DDS_PF_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 }, D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM }, + { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, + { { 32, DDS_PF_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, + { { 32, DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_R16G16_UNORM }, + { { 32, DDS_PF_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 }, D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }, D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }, D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM }, + { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 }, D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM }, + /* DDS_PF_INDEXED. */ + { { 32, DDS_PF_INDEXED, 0, 8 }, D3DX_PIXEL_FORMAT_P8_UINT }, + { { 32, DDS_PF_INDEXED | DDS_PF_ALPHA, 0, 16, 0, 0, 0, 0xff00, }, D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM }, + /* DDS_PF_LUMINANCE. */ + { { 32, DDS_PF_LUMINANCE, 0, 8, 0x00ff }, D3DX_PIXEL_FORMAT_L8_UNORM }, + { { 32, DDS_PF_LUMINANCE, 0, 16, 0xffff }, D3DX_PIXEL_FORMAT_L16_UNORM }, + { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x000f, 0, 0, 0x00f0 }, D3DX_PIXEL_FORMAT_L4A4_UNORM }, + { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, + /* Exceptional case, A8L8 can also have 8bpp. */ + { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, + /* DDS_PF_ALPHA_ONLY. */ + { { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, D3DX_PIXEL_FORMAT_A8_UNORM }, + /* DDS_PF_BUMPDUDV. */ + { { 32, DDS_PF_BUMPDUDV, 0, 16, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM }, + { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U16V16_SNORM }, + { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM }, + { { 32, DDS_PF_BUMPDUDV | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM }, + /* DDS_PF_BUMPLUMINANCE. */ + { { 32, DDS_PF_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM }, +}; + +static BOOL dds_pixel_format_compare(const struct dds_pixel_format *pf_a, const struct dds_pixel_format *pf_b, + BOOL check_rmask, BOOL check_gmask, BOOL check_bmask, BOOL check_amask) +{ + return pf_a->bpp == pf_b->bpp && !((check_rmask && pf_a->rmask != pf_b->rmask) + || (check_gmask && pf_a->gmask != pf_b->gmask) || (check_bmask && pf_a->bmask != pf_b->bmask) + || (check_amask && pf_a->amask != pf_b->amask)); +} + +static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dds_pixel_format(const struct dds_pixel_format *pixel_format) +{ + uint32_t i; + + TRACE("pixel_format: size %lu, flags %#lx, fourcc %#lx, bpp %lu.\n", pixel_format->size, + pixel_format->flags, pixel_format->fourcc, pixel_format->bpp); + TRACE("rmask %#lx, gmask %#lx, bmask %#lx, amask %#lx.\n", pixel_format->rmask, pixel_format->gmask, + pixel_format->bmask, pixel_format->amask); + + for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) + { + const struct dds_pixel_format *dds_pf = &dds_pixel_formats[i].dds_pixel_format; + + if (pixel_format->flags != dds_pf->flags) + continue; + + switch (pixel_format->flags & ~DDS_PF_ALPHA) + { + case DDS_PF_ALPHA_ONLY: + if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, TRUE)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_FOURCC: + if (pixel_format->fourcc == dds_pf->fourcc) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_INDEXED: + if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_RGB: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, pixel_format->flags & DDS_PF_ALPHA)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_LUMINANCE: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_BUMPLUMINANCE: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, FALSE)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + case DDS_PF_BUMPDUDV: + if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, TRUE)) + return dds_pixel_formats[i].d3dx_pixel_format; + break; + + default: + assert(0); /* Should not happen. */ + break; + } + } + + WARN("Unknown pixel format (flags %#lx, fourcc %#lx, bpp %lu, r %#lx, g %#lx, b %#lx, a %#lx).\n", + pixel_format->flags, pixel_format->fourcc, pixel_format->bpp, + pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); + return D3DX_PIXEL_FORMAT_COUNT; +} + +static HRESULT dds_pixel_format_from_d3dx_pixel_format_id(struct dds_pixel_format *pixel_format, + enum d3dx_pixel_format_id d3dx_pixel_format) +{ + const struct dds_pixel_format *pf = NULL; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) + { + if (dds_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) + { + pf = &dds_pixel_formats[i].dds_pixel_format; + break; + } + } + + if (!pf) + { + WARN("Unhandled format %#x.\n", d3dx_pixel_format); + return E_NOTIMPL; + } + + if (pixel_format) + *pixel_format = *pf; + + return D3D_OK; +} + +static void d3dx_get_next_mip_level_size(struct volume *size) +{ + size->width = max(size->width / 2, 1); + size->height = max(size->height / 2, 1); + size->depth = max(size->depth / 2, 1); +} + +static const char *debug_volume(const struct volume *volume) +{ + if (!volume) + return "(null)"; + return wine_dbg_sprintf("(%ux%ux%u)", volume->width, volume->height, volume->depth); +} + +static HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, + uint32_t *pitch, uint32_t *size) +{ + const struct pixel_format_desc *format_desc = get_d3dx_pixel_format_info(format); + + if (is_unknown_format(format_desc)) + return E_NOTIMPL; + + if (format_desc->block_width != 1 || format_desc->block_height != 1) + { + *pitch = format_desc->block_byte_count + * max(1, (width + format_desc->block_width - 1) / format_desc->block_width); + *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; + } + + return D3D_OK; +} + +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, + uint32_t mip_levels) +{ + uint32_t layer_size, row_pitch, slice_pitch, i; + struct volume dims = { width, height, depth }; + + layer_size = 0; + for (i = 0; i < mip_levels; ++i) + { + if (FAILED(d3dx_calculate_pixels_size(format, dims.width, dims.height, &row_pitch, &slice_pitch))) + return 0; + layer_size += slice_pitch * dims.depth; + d3dx_get_next_mip_level_size(&dims); + } + + return layer_size; +} + +HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, + enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels) +{ + HRESULT hr; + + 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) - FIELD_OFFSET(struct dds_header, size); + hr = dds_pixel_format_from_d3dx_pixel_format_id(&header->pixel_format, format); + if (FAILED(hr)) + return hr; + + header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT; + header->height = size->height; + header->width = size->width; + header->caps = DDS_CAPS_TEXTURE; + if (size->depth > 1) + { + header->flags |= DDS_DEPTH; + header->depth = size->depth; + header->caps2 |= DDS_CAPS2_VOLUME; + } + + if (mip_levels > 1) + { + header->flags |= DDS_MIPMAPCOUNT; + header->caps |= (DDS_CAPS_MIPMAP | DDS_CAPS_COMPLEX); + header->miplevels = mip_levels; + } + + if (resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) + { + header->caps |= DDS_CAPS_COMPLEX; + header->caps2 |= (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES); + } + + if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) + header->caps |= DDSCAPS_ALPHA; + if (header->pixel_format.flags & DDS_PF_INDEXED) + header->caps |= DDSCAPS_PALETTE; + + return D3D_OK; +} + +static const GUID *wic_container_guid_from_d3dx_file_format(enum d3dx_image_file_format iff) +{ + switch (iff) + { + case D3DX_IMAGE_FILE_FORMAT_DIB: + case D3DX_IMAGE_FILE_FORMAT_BMP: return &GUID_ContainerFormatBmp; + case D3DX_IMAGE_FILE_FORMAT_JPG: return &GUID_ContainerFormatJpeg; + case D3DX_IMAGE_FILE_FORMAT_PNG: return &GUID_ContainerFormatPng; + default: + assert(0 && "Unexpected file format."); + return NULL; + } +} + +static HRESULT d3dx_pixels_save_wic(struct d3dx_pixels *pixels, const struct pixel_format_desc *fmt_desc, + enum d3dx_image_file_format image_file_format, IStream **wic_file, uint32_t *wic_file_size) +{ + const GUID *container_format = wic_container_guid_from_d3dx_file_format(image_file_format); + const GUID *pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(fmt_desc->format); + IWICBitmapFrameEncode *wic_frame = NULL; + IPropertyBag2 *encoder_options = NULL; + IWICBitmapEncoder *wic_encoder = NULL; + WICPixelFormatGUID wic_pixel_format; + const LARGE_INTEGER seek = { 0 }; + IWICImagingFactory *wic_factory; + IWICPalette *wic_palette = NULL; + IStream *stream = NULL; + STATSTG stream_stats; + HRESULT hr; + + assert(container_format && pixel_format_guid); + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); + if (FAILED(hr)) + return D3DERR_INVALIDCALL; + + hr = IWICImagingFactory_CreateEncoder(wic_factory, container_format, NULL, &wic_encoder); + if (FAILED(hr)) + { + hr = D3DERR_INVALIDCALL; + goto exit; + } + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapEncoder_Initialize(wic_encoder, stream, WICBitmapEncoderNoCache); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapEncoder_CreateNewFrame(wic_encoder, &wic_frame, &encoder_options); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_Initialize(wic_frame, encoder_options); + if (FAILED(hr)) + goto exit; + + if (image_file_format == D3DX_IMAGE_FILE_FORMAT_JPG) + FIXME("JPEG saving quality adjustment currently unimplemented, expect lower quality JPEG.\n"); + + hr = IWICBitmapFrameEncode_SetSize(wic_frame, pixels->size.width, pixels->size.height); + if (FAILED(hr)) + goto exit; + + if (pixels->palette) + { + WICColor tmp_palette[256]; + unsigned int i; + + hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); + if (FAILED(hr)) + goto exit; + + for (i = 0; i < ARRAY_SIZE(tmp_palette); ++i) + { + const PALETTEENTRY *pe = &pixels->palette[i]; + + tmp_palette[i] = (pe->peFlags << 24) | (pe->peRed << 16) | (pe->peGreen << 8) | (pe->peBlue); + } + + hr = IWICPalette_InitializeCustom(wic_palette, tmp_palette, ARRAY_SIZE(tmp_palette)); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_SetPalette(wic_frame, wic_palette); + if (FAILED(hr)) + goto exit; + } + + /* + * Encode 32bpp BGRA format surfaces as 32bpp BGRX for BMP. + * This matches the behavior of native. + */ + if (IsEqualGUID(&GUID_ContainerFormatBmp, container_format) && (fmt_desc->format == D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM)) + pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM); + + wic_pixel_format = *pixel_format_guid; + hr = IWICBitmapFrameEncode_SetPixelFormat(wic_frame, &wic_pixel_format); + if (FAILED(hr)) + goto exit; + + if (!IsEqualGUID(pixel_format_guid, &wic_pixel_format)) + { + ERR("SetPixelFormat returned a different pixel format.\n"); + hr = E_FAIL; + goto exit; + } + + hr = IWICBitmapFrameEncode_WritePixels(wic_frame, pixels->size.height, pixels->row_pitch, pixels->slice_pitch, + (BYTE *)pixels->data); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameEncode_Commit(wic_frame); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapEncoder_Commit(wic_encoder); + if (FAILED(hr)) + goto exit; + + hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + goto exit; + + hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); + if (FAILED(hr)) + goto exit; + + if (!stream_stats.cbSize.u.HighPart && !!stream_stats.cbSize.u.LowPart) + { + *wic_file = stream; + *wic_file_size = stream_stats.cbSize.u.LowPart; + } + else + { + hr = D3DXERR_INVALIDDATA; + } + +exit: + if (wic_factory) + IWICImagingFactory_Release(wic_factory); + if (stream && (*wic_file != stream)) + IStream_Release(stream); + if (wic_frame) + IWICBitmapFrameEncode_Release(wic_frame); + if (wic_palette) + IWICPalette_Release(wic_palette); + if (encoder_options) + IPropertyBag2_Release(encoder_options); + if (wic_encoder) + IWICBitmapEncoder_Release(wic_encoder); + + return hr; +} + +static const enum d3dx_pixel_format_id tga_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM +}; + +static const enum d3dx_pixel_format_id png_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, + D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM +}; + +static const enum d3dx_pixel_format_id jpg_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, +}; + +static const enum d3dx_pixel_format_id bmp_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, + D3DX_PIXEL_FORMAT_B5G6R5_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, + D3DX_PIXEL_FORMAT_P8_UINT, +}; + +static const enum d3dx_pixel_format_id unimplemented_bmp_save_pixel_formats[] = +{ + D3DX_PIXEL_FORMAT_A8_UNORM, + D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, + D3DX_PIXEL_FORMAT_L8A8_UNORM, + D3DX_PIXEL_FORMAT_L16_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3_UNORM, + D3DX_PIXEL_FORMAT_R16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16_UNORM, + D3DX_PIXEL_FORMAT_R32_FLOAT, + D3DX_PIXEL_FORMAT_R32G32_FLOAT, + D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, + D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, + D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, + D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, + D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, +}; + +static enum d3dx_pixel_format_id d3dx_get_closest_d3dx_pixel_format_id(const enum d3dx_pixel_format_id *format_ids, + uint32_t format_ids_size, enum d3dx_pixel_format_id format_id) +{ + const struct pixel_format_desc *fmt, *curfmt, *bestfmt = NULL; + int bestscore = INT_MIN, rgb_channels, a_channel, i, j; + BOOL alpha_only, rgb_only; + + for (i = 0; i < format_ids_size; ++i) + { + if (format_ids[i] == format_id) + return format_id; + } + + TRACE("Requested format is not directly supported, looking for the best alternative.\n"); + switch (format_id) + { + case D3DX_PIXEL_FORMAT_P8_UINT: + case D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM: + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + fmt = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM); + break; + + default: + fmt = get_d3dx_pixel_format_info(format_id); + break; + } + + alpha_only = rgb_only = FALSE; + if (fmt->a_type != CTYPE_EMPTY && fmt->rgb_type == CTYPE_EMPTY) + alpha_only = TRUE; + else if (fmt->a_type == CTYPE_EMPTY && fmt->rgb_type != CTYPE_EMPTY) + rgb_only = TRUE; + + if (fmt->rgb_type == CTYPE_LUMA) + rgb_channels = 3; + else + rgb_channels = !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3]; + a_channel = !!fmt->bits[0]; + for (i = 0; i < format_ids_size; ++i) + { + int cur_rgb_channels, cur_a_channel, score; + + curfmt = get_d3dx_pixel_format_info(format_ids[i]); + if (!is_conversion_to_supported(curfmt)) + continue; + if (alpha_only && curfmt->a_type == CTYPE_EMPTY) + continue; + if (rgb_only && curfmt->rgb_type == CTYPE_EMPTY) + continue; + if (fmt->rgb_type == CTYPE_SNORM && curfmt->rgb_type != CTYPE_SNORM) + continue; + + cur_rgb_channels = !!curfmt->bits[1] + !!curfmt->bits[2] + !!curfmt->bits[3]; + cur_a_channel = !!curfmt->bits[0]; + /* Calculate a score for this format. */ + score = 512 * (format_types_match(curfmt, fmt)); + score -= 32 * abs(cur_a_channel - a_channel); + score -= 32 * abs(cur_rgb_channels - rgb_channels); + for (j = 0; j < 4; ++j) + { + int diff = curfmt->bits[j] - fmt->bits[j]; + + score -= (diff < 0 ? -diff * 8 : diff) * (j == 0 ? 1 : 2); + } + + if (score > bestscore) + { + bestscore = score; + bestfmt = curfmt; + } + } + + return (bestfmt) ? bestfmt->format : D3DX_PIXEL_FORMAT_COUNT; +} + +HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, + enum d3dx_image_file_format file_format, ID3DXBuffer **dst_buffer) +{ + enum d3dx_pixel_format_id dst_format = src_fmt_desc->format; + const struct pixel_format_desc *dst_fmt_desc; + uint32_t dst_row_pitch, dst_slice_pitch; + struct d3dx_pixels dst_pixels; + uint8_t *pixels, *tmp_buf; + ID3DXBuffer *buffer; + HRESULT hr; + + *dst_buffer = buffer = NULL; + pixels = tmp_buf = NULL; + switch (file_format) + { + case D3DX_IMAGE_FILE_FORMAT_DDS: + hr = dds_pixel_format_from_d3dx_pixel_format_id(NULL, dst_format); + if (FAILED(hr)) + return hr; + break; + + case D3DX_IMAGE_FILE_FORMAT_TGA: + dst_format = d3dx_get_closest_d3dx_pixel_format_id(tga_save_pixel_formats, ARRAY_SIZE(tga_save_pixel_formats), + dst_format); + break; + + case D3DX_IMAGE_FILE_FORMAT_PNG: + dst_format = d3dx_get_closest_d3dx_pixel_format_id(png_save_pixel_formats, ARRAY_SIZE(png_save_pixel_formats), + dst_format); + break; + + case D3DX_IMAGE_FILE_FORMAT_JPG: + dst_format = d3dx_get_closest_d3dx_pixel_format_id(jpg_save_pixel_formats, ARRAY_SIZE(jpg_save_pixel_formats), + dst_format); + break; + + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_DIB: + { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(unimplemented_bmp_save_pixel_formats); ++i) + { + if (unimplemented_bmp_save_pixel_formats[i] == dst_format) + { + FIXME("Saving pixel format %d to BMP files is currently unsupported.\n", dst_format); + return E_NOTIMPL; + } + } + dst_format = d3dx_get_closest_d3dx_pixel_format_id(bmp_save_pixel_formats, ARRAY_SIZE(bmp_save_pixel_formats), + dst_format); + break; + } + + default: + assert(0 && "Unexpected file format."); + return E_FAIL; + } + + if (dst_format == D3DX_PIXEL_FORMAT_COUNT) + { + WARN("Failed to find adequate replacement format for saving.\n"); + return D3DERR_INVALIDCALL; + } + + if (dst_format != src_fmt_desc->format && !is_conversion_from_supported(src_fmt_desc)) + { + FIXME("Cannot convert d3dx pixel format %d, can't save.\n", src_fmt_desc->format); + return E_NOTIMPL; + } + + dst_fmt_desc = get_d3dx_pixel_format_info(dst_format); + src_pixels->size.depth = (file_format == D3DX_IMAGE_FILE_FORMAT_DDS) ? src_pixels->size.depth : 1; + hr = d3dx_calculate_pixels_size(dst_format, src_pixels->size.width, src_pixels->size.height, &dst_row_pitch, + &dst_slice_pitch); + if (FAILED(hr)) + return hr; + + switch (file_format) + { + case D3DX_IMAGE_FILE_FORMAT_DDS: + { + struct dds_header *header; + uint32_t header_size; + + header_size = is_index_format(dst_fmt_desc) ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); + hr = D3DXCreateBuffer((dst_slice_pitch * src_pixels->size.depth) + header_size, &buffer); + if (FAILED(hr)) + return hr; + + header = ID3DXBuffer_GetBufferPointer(buffer); + pixels = (uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + header_size; + hr = d3dx_init_dds_header(header, D3DX_RESOURCE_TYPE_TEXTURE_2D, dst_format, &src_pixels->size, 1); + if (FAILED(hr)) + goto exit; + if (is_index_format(dst_fmt_desc)) + memcpy((uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(*header), src_pixels->palette, + DDS_PALETTE_SIZE); + break; + } + + case D3DX_IMAGE_FILE_FORMAT_TGA: + { + struct tga_header *header; + + hr = D3DXCreateBuffer(dst_slice_pitch + sizeof(*header), &buffer); + if (FAILED(hr)) + return hr; + + header = ID3DXBuffer_GetBufferPointer(buffer); + pixels = (uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(*header); + + memset(header, 0, sizeof(*header)); + header->image_type = TGA_IMAGETYPE_TRUECOLOR; + header->width = src_pixels->size.width; + header->height = src_pixels->size.height; + header->image_descriptor = TGA_IMAGE_TOPTOBOTTOM; + header->depth = dst_fmt_desc->bytes_per_pixel * 8; + if (dst_fmt_desc->format == D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) + header->image_descriptor |= 0x08; + break; + } + + case D3DX_IMAGE_FILE_FORMAT_PNG: + case D3DX_IMAGE_FILE_FORMAT_JPG: + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_DIB: + if (src_fmt_desc == dst_fmt_desc) + dst_pixels = *src_pixels; + else + pixels = tmp_buf = malloc(dst_slice_pitch); + break; + + default: + break; + } + + if (src_pixels->size.width != 0 && src_pixels->size.height != 0) + { + if (pixels) + { + const PALETTEENTRY *dst_palette = is_index_format(dst_fmt_desc) ? src_pixels->palette : NULL; + const RECT dst_rect = { 0, 0, src_pixels->size.width, src_pixels->size.height }; + + set_d3dx_pixels(&dst_pixels, pixels, dst_row_pitch, dst_slice_pitch, dst_palette, + src_pixels->size.width, src_pixels->size.height, src_pixels->size.depth, &dst_rect); + + hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_fmt_desc, src_pixels, src_fmt_desc, D3DX_FILTER_NONE, 0); + if (FAILED(hr)) + goto exit; + } + + /* WIC path, encode the image. */ + if (!buffer) + { + IStream *wic_file = NULL; + uint32_t buf_size = 0; + + hr = d3dx_pixels_save_wic(&dst_pixels, dst_fmt_desc, file_format, &wic_file, &buf_size); + if (FAILED(hr)) + goto exit; + hr = D3DXCreateBuffer(buf_size, &buffer); + if (FAILED(hr)) + { + IStream_Release(wic_file); + goto exit; + } + + hr = IStream_Read(wic_file, ID3DXBuffer_GetBufferPointer(buffer), buf_size, NULL); + IStream_Release(wic_file); + if (FAILED(hr)) + goto exit; + } + } + /* Return an empty buffer for size 0 images via WIC. */ + else if (!buffer) + { + FIXME("Returning empty buffer for size 0 image.\n"); + hr = D3DXCreateBuffer(64, &buffer); + if (FAILED(hr)) + goto exit; + } + + *dst_buffer = buffer; +exit: + free(tmp_buf); + if (*dst_buffer != buffer) + ID3DXBuffer_Release(buffer); + return hr; +} + +static const uint8_t bmp_file_signature[] = { 'B', 'M' }; +static const uint8_t jpg_file_signature[] = { 0xff, 0xd8 }; +static const uint8_t png_file_signature[] = { 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a }; +static const uint8_t dds_file_signature[] = { 'D', 'D', 'S', ' ' }; +static const uint8_t ppm_plain_file_signature[] = { 'P', '3' }; +static const uint8_t ppm_raw_file_signature[] = { 'P', '6' }; +static const uint8_t hdr_file_signature[] = { '#', '?', 'R', 'A', 'D', 'I', 'A', 'N', 'C', 'E', '\n' }; +static const uint8_t pfm_color_file_signature[] = { 'P', 'F' }; +static const uint8_t pfm_gray_file_signature[] = { 'P', 'f' }; + +/* + * If none of these match, the file is either DIB, TGA, or something we don't + * support. + */ +struct d3dx_file_format_signature +{ + const uint8_t *file_signature; + uint32_t file_signature_len; + enum d3dx_image_file_format image_file_format; +}; + +static const struct d3dx_file_format_signature file_format_signatures[] = +{ + { bmp_file_signature, sizeof(bmp_file_signature), D3DX_IMAGE_FILE_FORMAT_BMP }, + { jpg_file_signature, sizeof(jpg_file_signature), D3DX_IMAGE_FILE_FORMAT_JPG }, + { png_file_signature, sizeof(png_file_signature), D3DX_IMAGE_FILE_FORMAT_PNG }, + { dds_file_signature, sizeof(dds_file_signature), D3DX_IMAGE_FILE_FORMAT_DDS }, + { ppm_plain_file_signature, sizeof(ppm_plain_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, + { ppm_raw_file_signature, sizeof(ppm_raw_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, + { hdr_file_signature, sizeof(hdr_file_signature), D3DX_IMAGE_FILE_FORMAT_HDR }, + { pfm_color_file_signature, sizeof(pfm_color_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, + { pfm_gray_file_signature, sizeof(pfm_gray_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, +}; + +static BOOL d3dx_get_image_file_format_from_file_signature(const void *src_data, uint32_t src_data_size, + enum d3dx_image_file_format *out_iff) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(file_format_signatures); ++i) + { + const struct d3dx_file_format_signature *signature = &file_format_signatures[i]; + + if ((src_data_size >= signature->file_signature_len) + && !memcmp(src_data, signature->file_signature, signature->file_signature_len)) + { + *out_iff = signature->image_file_format; + return TRUE; + } + } + + return FALSE; +} + +static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image, uint32_t starting_mip_level) +{ + uint32_t expected_src_data_size, header_size; + const struct dds_header *header = src_data; + BOOL is_indexed_fmt; + HRESULT hr; + + if (src_data_size < sizeof(*header) || header->pixel_format.size != sizeof(header->pixel_format)) + return D3DXERR_INVALIDDATA; + + TRACE("File type is DDS.\n"); + is_indexed_fmt = !!(header->pixel_format.flags & DDS_PF_INDEXED); + header_size = is_indexed_fmt ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); + + set_volume_struct(&image->size, header->width, header->height, 1); + image->mip_levels = header->miplevels ? header->miplevels : 1; + image->format = d3dx_pixel_format_id_from_dds_pixel_format(&header->pixel_format); + image->layer_count = 1; + + if (image->format == D3DX_PIXEL_FORMAT_COUNT) + return D3DXERR_INVALIDDATA; + + TRACE("Pixel format is %#x.\n", image->format); + if (header->flags & DDS_DEPTH) + { + image->size.depth = max(header->depth, 1); + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_3D; + } + else if (header->caps2 & DDS_CAPS2_CUBEMAP) + { + if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES) + { + WARN("Tried to load a partial cubemap DDS file.\n"); + return D3DXERR_INVALIDDATA; + } + + image->layer_count = 6; + image->resource_type = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; + } + else + { + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + } + + image->layer_pitch = d3dx_calculate_layer_pixels_size(image->format, image->size.width, image->size.height, + image->size.depth, image->mip_levels); + if (!image->layer_pitch) + return D3DXERR_INVALIDDATA; + expected_src_data_size = (image->layer_pitch * image->layer_count) + header_size; + 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->palette = (is_indexed_fmt) ? (PALETTEENTRY *)(((uint8_t *)src_data) + sizeof(*header)) : NULL; + image->pixels = ((BYTE *)src_data) + header_size; + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DDS; + if (starting_mip_level && (image->mip_levels > 1)) + { + uint32_t i, row_pitch, slice_pitch, initial_mip_levels; + const struct volume initial_size = image->size; + + initial_mip_levels = image->mip_levels; + for (i = 0; i < starting_mip_level; i++) + { + hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + image->pixels += slice_pitch * image->size.depth; + d3dx_get_next_mip_level_size(&image->size); + if (--image->mip_levels == 1) + break; + } + + TRACE("Requested starting mip level %u, actual starting mip level is %u (of %u total in image).\n", + starting_mip_level, (initial_mip_levels - image->mip_levels), initial_mip_levels); + TRACE("Original dimensions %s, new dimensions %s.\n", debug_volume(&initial_size), debug_volume(&image->size)); + } + + return D3D_OK; +} + +static BOOL convert_dib_to_bmp(const void **data, unsigned int *size) +{ + ULONG header_size; + ULONG count = 0; + ULONG offset; + BITMAPFILEHEADER *header; + BYTE *new_data; + UINT new_size; + + if ((*size < 4) || (*size < (header_size = *(ULONG*)*data))) + return FALSE; + + if ((header_size == sizeof(BITMAPINFOHEADER)) || + (header_size == sizeof(BITMAPV4HEADER)) || + (header_size == sizeof(BITMAPV5HEADER)) || + (header_size == 64 /* sizeof(BITMAPCOREHEADER2) */)) + { + /* All structures begin with the same memory layout as BITMAPINFOHEADER */ + BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER*)*data; + count = info_header->biClrUsed; + + if (!count && info_header->biBitCount <= 8) + count = 1 << info_header->biBitCount; + + offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBQUAD) * count; + + /* For BITMAPINFOHEADER with BI_BITFIELDS compression, there are 3 additional color masks after header */ + if ((info_header->biSize == sizeof(BITMAPINFOHEADER)) && (info_header->biCompression == BI_BITFIELDS)) + offset += 3 * sizeof(DWORD); + } + else if (header_size == sizeof(BITMAPCOREHEADER)) + { + BITMAPCOREHEADER *core_header = (BITMAPCOREHEADER*)*data; + + if (core_header->bcBitCount <= 8) + count = 1 << core_header->bcBitCount; + + offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBTRIPLE) * count; + } + else + { + return FALSE; + } + + TRACE("Converting DIB file to BMP\n"); + + new_size = *size + sizeof(BITMAPFILEHEADER); + new_data = malloc(new_size); + CopyMemory(new_data + sizeof(BITMAPFILEHEADER), *data, *size); + + /* Add BMP header */ + header = (BITMAPFILEHEADER*)new_data; + header->bfType = 0x4d42; /* BM */ + header->bfSize = new_size; + header->bfReserved1 = 0; + header->bfReserved2 = 0; + header->bfOffBits = offset; + + /* Update input data */ + *data = new_data; + *size = new_size; + + return TRUE; +} + +/* 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, struct d3dx_image *image) +{ + unsigned int size, i; + BYTE *buffer; + HRESULT hr; + + if (image->format != D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM || image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) + return FALSE; + + size = image->size.width * image->size.height * 4; + if (!(buffer = malloc(size))) + return FALSE; + + if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->size.width * 4, size, buffer))) + { + ERR("Failed to copy pixels, hr %#lx.\n", hr); + free(buffer); + return FALSE; + } + + for (i = 0; i < image->size.width * image->size.height; ++i) + { + if (buffer[i * 4 + 3]) + { + free(buffer); + return TRUE; + } + } + + free(buffer); + return FALSE; +} + +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format) +{ + switch (format) + { +#define FMT_TO_STR(format) case format: return #format + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_BMP); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_JPG); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_TGA); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PNG); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DDS); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PPM); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DIB); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_HDR); + FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PFM); +#undef FMT_TO_STR + default: + return "unrecognized"; + } +} + +static HRESULT d3dx_image_wic_frame_decode(struct d3dx_image *image, + IWICImagingFactory *wic_factory, IWICBitmapFrameDecode *bitmap_frame) +{ + const struct pixel_format_desc *fmt_desc; + uint32_t row_pitch, slice_pitch; + IWICPalette *wic_palette = NULL; + PALETTEENTRY *palette = NULL; + WICColor *colors = NULL; + BYTE *buffer = NULL; + HRESULT hr; + + fmt_desc = get_d3dx_pixel_format_info(image->format); + hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + /* Allocate a buffer for our image. */ + if (!(buffer = malloc(slice_pitch))) + return E_OUTOFMEMORY; + + hr = IWICBitmapFrameDecode_CopyPixels(bitmap_frame, NULL, row_pitch, slice_pitch, buffer); + if (FAILED(hr)) + { + free(buffer); + return hr; + } + + if (is_index_format(fmt_desc)) + { + uint32_t nb_colors, i; + + hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_CopyPalette(bitmap_frame, wic_palette); + if (FAILED(hr)) + goto exit; + + hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); + if (FAILED(hr)) + goto exit; + + colors = malloc(nb_colors * sizeof(colors[0])); + palette = malloc(256 * sizeof(palette[0])); + if (!colors || !palette) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); + if (FAILED(hr)) + goto exit; + + /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ + for (i = 0; i < nb_colors; i++) + { + palette[i].peRed = (colors[i] >> 16) & 0xff; + palette[i].peGreen = (colors[i] >> 8) & 0xff; + palette[i].peBlue = colors[i] & 0xff; + palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ + } + if (nb_colors < 256) + memset(&palette[nb_colors], 0xff, sizeof(*palette) * (256 - nb_colors)); + } + + image->image_buf = image->pixels = buffer; + image->image_palette = image->palette = palette; + +exit: + free(colors); + if (image->image_buf != buffer) + free(buffer); + if (image->image_palette != palette) + free(palette); + if (wic_palette) + IWICPalette_Release(wic_palette); + + return hr; +} + +static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, + struct d3dx_image *image, enum d3dx_image_file_format d3dx_file_format, uint32_t flags) +{ + const GUID *container_format_guid = wic_container_guid_from_d3dx_file_format(d3dx_file_format); + IWICBitmapFrameDecode *bitmap_frame = NULL; + IWICBitmapDecoder *bitmap_decoder = NULL; + IWICImagingFactory *wic_factory; + WICPixelFormatGUID pixel_format; + IWICStream *wic_stream = NULL; + uint32_t frame_count = 0; + HRESULT hr; + + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); + if (FAILED(hr)) + return hr; + + hr = IWICImagingFactory_CreateDecoder(wic_factory, container_format_guid, NULL, &bitmap_decoder); + if (FAILED(hr)) + goto exit; + + hr = IWICImagingFactory_CreateStream(wic_factory, &wic_stream); + if (FAILED(hr)) + goto exit; + + hr = IWICStream_InitializeFromMemory(wic_stream, (BYTE *)src_data, src_data_size); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapDecoder_Initialize(bitmap_decoder, (IStream *)wic_stream, 0); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); + if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) + { + hr = D3DXERR_INVALIDDATA; + goto exit; + } + + image->image_file_format = d3dx_file_format; + hr = IWICBitmapDecoder_GetFrame(bitmap_decoder, 0, &bitmap_frame); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->size.width, &image->size.height); + if (FAILED(hr)) + goto exit; + + hr = IWICBitmapFrameDecode_GetPixelFormat(bitmap_frame, &pixel_format); + if (FAILED(hr)) + goto exit; + + image->format = d3dx_pixel_format_id_from_wic_pixel_format(&pixel_format); + switch (image->format) + { + case D3DX_PIXEL_FORMAT_P2_UINT: + if (image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) + break; + /* Fall through. */ + + case D3DX_PIXEL_FORMAT_COUNT: + WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); + hr = D3DXERR_INVALIDDATA; + goto exit; + + default: + break; + } + + if (image_is_argb(bitmap_frame, image)) + image->format = D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + + if (!(flags & D3DX_IMAGE_INFO_ONLY)) + { + hr = d3dx_image_wic_frame_decode(image, wic_factory, bitmap_frame); + if (FAILED(hr)) + goto exit; + } + + image->size.depth = 1; + image->mip_levels = 1; + image->layer_count = 1; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + +exit: + if (bitmap_frame) + IWICBitmapFrameDecode_Release(bitmap_frame); + if (bitmap_decoder) + IWICBitmapDecoder_Release(bitmap_decoder); + if (wic_stream) + IWICStream_Release(wic_stream); + IWICImagingFactory_Release(wic_factory); + + return hr; +} + +static enum d3dx_pixel_format_id d3dx_get_tga_format_for_bpp(uint8_t bpp) +{ + switch (bpp) + { + case 15: return D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM; + case 16: return D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM; + case 24: return D3DX_PIXEL_FORMAT_B8G8R8_UNORM; + case 32: return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; + default: + WARN("Unhandled bpp %u for targa.\n", bpp); + return D3DX_PIXEL_FORMAT_COUNT; + } +} + +static HRESULT d3dx_image_tga_rle_decode_row(const uint8_t **src, uint32_t src_bytes_left, uint32_t row_width, + uint32_t bytes_per_pixel, uint8_t *dst_row) +{ + const uint8_t *src_ptr = *src; + uint32_t pixel_count = 0; + + while (pixel_count != row_width) + { + uint32_t rle_count = (src_ptr[0] & 0x7f) + 1; + uint32_t rle_packet_size = 1; + + rle_packet_size += (src_ptr[0] & 0x80) ? bytes_per_pixel : (bytes_per_pixel * rle_count); + if ((rle_packet_size > src_bytes_left) || (pixel_count + rle_count) > row_width) + return D3DXERR_INVALIDDATA; + + if (src_ptr[0] & 0x80) + { + uint32_t i; + + for (i = 0; i < rle_count; ++i) + memcpy(&dst_row[(pixel_count + i) * bytes_per_pixel], src_ptr + 1, bytes_per_pixel); + } + else + { + memcpy(&dst_row[pixel_count * bytes_per_pixel], src_ptr + 1, rle_packet_size - 1); + } + + src_ptr += rle_packet_size; + src_bytes_left -= rle_packet_size; + pixel_count += rle_count; + if (!src_bytes_left && pixel_count != row_width) + return D3DXERR_INVALIDDATA; + } + + *src = src_ptr; + return D3D_OK; +} + +struct d3dx_color_key; +static 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, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key, + const PALETTEENTRY *palette); +static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, + struct d3dx_image *image) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(image->format); + const struct tga_header *header = (const struct tga_header *)src_data; + const BOOL right_to_left = !!(header->image_descriptor & TGA_IMAGE_RIGHTTOLEFT); + const BOOL bottom_to_top = !(header->image_descriptor & TGA_IMAGE_TOPTOBOTTOM); + const BOOL is_rle = !!(header->image_type & TGA_IMAGETYPE_RLE); + uint8_t *img_buf = NULL, *src_row = NULL; + uint32_t row_pitch, slice_pitch, i; + PALETTEENTRY *palette = NULL; + const uint8_t *src_pos; + HRESULT hr; + + hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + /* File is too small. */ + if (!is_rle && (src_header_size + slice_pitch) > src_data_size) + return D3DXERR_INVALIDDATA; + + if (image->format == D3DX_PIXEL_FORMAT_P8_UINT) + { + const uint8_t *src_palette = ((const uint8_t *)src_data) + sizeof(*header) + header->id_length; + const struct volume image_map_size = { header->color_map_length, 1, 1 }; + uint32_t src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch; + const struct pixel_format_desc *src_desc, *dst_desc; + + if (!(palette = malloc(sizeof(*palette) * 256))) + return E_OUTOFMEMORY; + + /* + * Convert from a TGA colormap to PALETTEENTRY. TGA is BGRA, + * PALETTEENTRY is RGBA. + */ + src_desc = get_d3dx_pixel_format_info(d3dx_get_tga_format_for_bpp(header->color_map_entrysize)); + hr = d3dx_calculate_pixels_size(src_desc->format, header->color_map_length, 1, &src_row_pitch, &src_slice_pitch); + if (FAILED(hr)) + goto exit; + + dst_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + d3dx_calculate_pixels_size(dst_desc->format, 256, 1, &dst_row_pitch, &dst_slice_pitch); + convert_argb_pixels(src_palette, src_row_pitch, src_slice_pitch, &image_map_size, src_desc, (BYTE *)palette, + dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, NULL, NULL); + + /* Initialize unused palette entries to 0xff. */ + if (header->color_map_length < 256) + memset(&palette[header->color_map_length], 0xff, sizeof(*palette) * (256 - header->color_map_length)); + } + + if (!is_rle && !bottom_to_top && !right_to_left) + { + image->pixels = (uint8_t *)src_data + src_header_size; + image->image_palette = image->palette = palette; + return D3D_OK; + } + + if (!(img_buf = malloc(slice_pitch))) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + /* Allocate an extra row to use as a temporary buffer. */ + if (is_rle) + { + if (!(src_row = malloc(row_pitch))) + { + hr = E_OUTOFMEMORY; + goto exit; + } + } + + src_pos = (const uint8_t *)src_data + src_header_size; + for (i = 0; i < image->size.height; ++i) + { + const uint32_t dst_row_idx = bottom_to_top ? (image->size.height - i - 1) : i; + uint8_t *dst_row = img_buf + (dst_row_idx * row_pitch); + + if (is_rle) + { + hr = d3dx_image_tga_rle_decode_row(&src_pos, src_data_size - (src_pos - (const uint8_t *)src_data), + image->size.width, fmt_desc->bytes_per_pixel, src_row); + if (FAILED(hr)) + goto exit; + } + else + { + src_row = (uint8_t *)src_pos; + src_pos += row_pitch; + } + + if (right_to_left) + { + const uint8_t *src_pixel = &src_row[((image->size.width - 1)) * fmt_desc->bytes_per_pixel]; + uint8_t *dst_pixel = dst_row; + uint32_t j; + + for (j = 0; j < image->size.width; ++j) + { + memcpy(dst_pixel, src_pixel, fmt_desc->bytes_per_pixel); + src_pixel -= fmt_desc->bytes_per_pixel; + dst_pixel += fmt_desc->bytes_per_pixel; + } + } + else + { + memcpy(dst_row, src_row, row_pitch); + } + } + + image->image_buf = image->pixels = img_buf; + image->image_palette = image->palette = palette; + +exit: + if (is_rle) + free(src_row); + if (img_buf && (image->image_buf != img_buf)) + free(img_buf); + if (palette && (image->image_palette != palette)) + free(palette); + + return hr; +} + +static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, + uint32_t flags) +{ + const struct tga_header *header = (const struct tga_header *)src_data; + uint32_t expected_header_size = sizeof(*header); + + if (src_data_size < sizeof(*header)) + return D3DXERR_INVALIDDATA; + + expected_header_size += header->id_length; + expected_header_size += header->color_map_length * ((header->color_map_entrysize + 7) / CHAR_BIT); + if (src_data_size < expected_header_size) + return D3DXERR_INVALIDDATA; + + if (header->color_map_type && ((header->color_map_type > 1) || (!header->color_map_length) + || (d3dx_get_tga_format_for_bpp(header->color_map_entrysize) == D3DX_PIXEL_FORMAT_COUNT))) + return D3DXERR_INVALIDDATA; + + switch (header->image_type & TGA_IMAGETYPE_MASK) + { + case TGA_IMAGETYPE_COLORMAPPED: + if (header->depth != 8 || !header->color_map_type) + return D3DXERR_INVALIDDATA; + image->format = D3DX_PIXEL_FORMAT_P8_UINT; + break; + + case TGA_IMAGETYPE_TRUECOLOR: + if ((image->format = d3dx_get_tga_format_for_bpp(header->depth)) == D3DX_PIXEL_FORMAT_COUNT) + return D3DXERR_INVALIDDATA; + break; + + case TGA_IMAGETYPE_GRAYSCALE: + if (header->depth != 8) + return D3DXERR_INVALIDDATA; + image->format = D3DX_PIXEL_FORMAT_L8_UNORM; + break; + + default: + return D3DXERR_INVALIDDATA; + } + + set_volume_struct(&image->size, header->width, header->height, 1); + image->mip_levels = 1; + image->layer_count = 1; + image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_TGA; + + if (!(flags & D3DX_IMAGE_INFO_ONLY)) + return d3dx_image_tga_decode(src_data, src_data_size, expected_header_size, image); + + return D3D_OK; +} + +HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, + uint32_t starting_mip_level, uint32_t flags) +{ + enum d3dx_image_file_format iff = D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD; + HRESULT hr; + + if (!src_data || !src_data_size || !image) + return D3DERR_INVALIDCALL; + + memset(image, 0, sizeof(*image)); + if (!d3dx_get_image_file_format_from_file_signature(src_data, src_data_size, &iff)) + { + uint32_t src_image_size = src_data_size; + const void *src_image = src_data; + + if (convert_dib_to_bmp(&src_image, &src_image_size)) + { + hr = d3dx_image_init(src_image, src_image_size, image, starting_mip_level, flags); + free((void *)src_image); + if (SUCCEEDED(hr)) + image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DIB; + return hr; + } + + /* Last resort, try TGA. */ + return d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); + } + + switch (iff) + { + case D3DX_IMAGE_FILE_FORMAT_BMP: + case D3DX_IMAGE_FILE_FORMAT_JPG: + case D3DX_IMAGE_FILE_FORMAT_PNG: + hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, iff, flags); + break; + + case D3DX_IMAGE_FILE_FORMAT_DDS: + hr = d3dx_initialize_image_from_dds(src_data, src_data_size, image, starting_mip_level); + break; + + case D3DX_IMAGE_FILE_FORMAT_PPM: + case D3DX_IMAGE_FILE_FORMAT_HDR: + case D3DX_IMAGE_FILE_FORMAT_PFM: + WARN("Unsupported file format %s.\n", debug_d3dx_image_file_format(iff)); + hr = E_NOTIMPL; + break; + + case D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD: + ERR("Unrecognized file format.\n"); + hr = D3DXERR_INVALIDDATA; + break; + + default: + assert(0); + return E_FAIL; + } + + return hr; +} + +void d3dx_image_cleanup(struct d3dx_image *image) +{ + free(image->image_buf); + free(image->image_palette); +} + +HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, + struct d3dx_pixels *pixels) +{ + struct volume mip_level_size = image->size; + const BYTE *pixels_ptr = image->pixels; + uint32_t row_pitch, slice_pitch, i; + RECT unaligned_rect; + HRESULT hr = S_OK; + + if (mip_level >= image->mip_levels) + { + ERR("Tried to retrieve mip level %u, but image only has %u mip levels.\n", mip_level, image->mip_levels); + return E_FAIL; + } + + if (layer >= image->layer_count) + { + ERR("Tried to retrieve layer %u, but image only has %u layers.\n", layer, image->layer_count); + return E_FAIL; + } + + slice_pitch = row_pitch = 0; + for (i = 0; i < image->mip_levels; i++) + { + hr = d3dx_calculate_pixels_size(image->format, mip_level_size.width, mip_level_size.height, &row_pitch, &slice_pitch); + if (FAILED(hr)) + return hr; + + if (i == mip_level) + break; + + pixels_ptr += slice_pitch * mip_level_size.depth; + d3dx_get_next_mip_level_size(&mip_level_size); + } + + pixels_ptr += (layer * image->layer_pitch); + SetRect(&unaligned_rect, 0, 0, mip_level_size.width, mip_level_size.height); + set_d3dx_pixels(pixels, pixels_ptr, row_pitch, slice_pitch, image->palette, mip_level_size.width, + mip_level_size.height, mip_level_size.depth, &unaligned_rect); + + return D3D_OK; +} + +unsigned short float_32_to_16(const float in) +{ + int exp = 0, origexp; + float tmp = fabsf(in); + int sign = (copysignf(1, in) < 0); + unsigned int mantissa; + unsigned short ret; + + /* Deal with special numbers */ + if (isinf(in)) return (sign ? 0xffff : 0x7fff); + if (isnan(in)) return (sign ? 0xffff : 0x7fff); + if (in == 0.0f) return (sign ? 0x8000 : 0x0000); + + if (tmp < (float)(1u << 10)) + { + do + { + tmp *= 2.0f; + exp--; + } while (tmp < (float)(1u << 10)); + } + else if (tmp >= (float)(1u << 11)) + { + do + { + tmp /= 2.0f; + exp++; + } while (tmp >= (float)(1u << 11)); + } + + exp += 10; /* Normalize the mantissa */ + exp += 15; /* Exponent is encoded with excess 15 */ + + origexp = exp; + + mantissa = (unsigned int) tmp; + if ((tmp - mantissa == 0.5f && mantissa % 2 == 1) || /* round half to even */ + (tmp - mantissa > 0.5f)) + { + mantissa++; /* round to nearest, away from zero */ + } + if (mantissa == 2048) + { + mantissa = 1024; + exp++; + } + + if (exp > 31) + { + /* too big */ + ret = 0x7fff; /* INF */ + } + else if (exp <= 0) + { + unsigned int rounding = 0; + + /* Denormalized half float */ + + /* return 0x0000 (=0.0) for numbers too small to represent in half floats */ + if (exp < -11) + return (sign ? 0x8000 : 0x0000); + + exp = origexp; + + /* the 13 extra bits from single precision are used for rounding */ + mantissa = (unsigned int)(tmp * (1u << 13)); + mantissa >>= 1 - exp; /* denormalize */ + + mantissa -= ~(mantissa >> 13) & 1; /* round half to even */ + /* remove 13 least significant bits to get half float precision */ + mantissa >>= 12; + rounding = mantissa & 1; + mantissa >>= 1; + + ret = mantissa + rounding; + } + else + { + ret = (exp << 10) | (mantissa & 0x3ff); + } + + ret |= ((sign ? 1 : 0) << 15); /* Add the sign */ + return ret; +} + +/* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a + * regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */ +float float_16_to_32(const unsigned short in) +{ + const unsigned short s = (in & 0x8000); + const unsigned short e = (in & 0x7C00) >> 10; + const unsigned short m = in & 0x3FF; + const float sgn = (s ? -1.0f : 1.0f); + + if (e == 0) + { + if (m == 0) return sgn * 0.0f; /* +0.0 or -0.0 */ + else return sgn * powf(2, -14.0f) * (m / 1024.0f); + } + else + { + return sgn * powf(2, e - 15.0f) * (1.0f + (m / 1024.0f)); + } +} + +struct argb_conversion_info +{ + const struct pixel_format_desc *srcformat; + const struct pixel_format_desc *destformat; + DWORD srcshift[4], destshift[4]; + DWORD srcmask[4], destmask[4]; + BOOL process_channel[4]; + DWORD channelmask; +}; + +static void init_argb_conversion_info(const struct pixel_format_desc *srcformat, const struct pixel_format_desc *destformat, struct argb_conversion_info *info) +{ + UINT i; + ZeroMemory(info->process_channel, 4 * sizeof(BOOL)); + info->channelmask = 0; + + info->srcformat = srcformat; + info->destformat = destformat; + + for(i = 0;i < 4;i++) { + /* srcshift is used to extract the _relevant_ components */ + info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0); + + /* destshift is used to move the components to the correct position */ + info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0); + + info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i]; + info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i]; + + /* channelmask specifies bits which aren't used in the source format but in the destination one */ + if(destformat->bits[i]) { + if(srcformat->bits[i]) info->process_channel[i] = TRUE; + else info->channelmask |= info->destmask[i]; + } + } +} + +/************************************************************ + * get_relevant_argb_components + * + * 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, const BYTE *col, DWORD *out) +{ + 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; + } +} + +static float d3dx_clamp(float value, float min_value, float max_value) +{ + if (isnan(value)) + return max_value; + return value < min_value ? min_value : value > max_value ? max_value : value; +} + +/************************************************************ + * make_argb_color + * + * Recombines the output of get_relevant_argb_components and converts + * it to the destination format. + */ +static DWORD make_argb_color(const struct argb_conversion_info *info, const DWORD *in) +{ + UINT i; + DWORD val = 0; + + for(i = 0;i < 4;i++) { + if(info->process_channel[i]) { + /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */ + signed int shift; + for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift; + val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i]; + } + } + val |= info->channelmask; /* new channels are set to their maximal value */ + return val; +} + +static enum range get_range_for_component_type(enum component_type type) +{ + switch (type) + { + case CTYPE_SNORM: + return RANGE_SNORM; + + case CTYPE_LUMA: + case CTYPE_INDEX: + case CTYPE_UNORM: + return RANGE_UNORM; + + case CTYPE_EMPTY: + case CTYPE_FLOAT: + return RANGE_FULL; + + default: + assert(0); + return RANGE_FULL; + } +} + +/* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */ +void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, + struct d3dx_color *dst) +{ + DWORD mask, tmp; + unsigned int c; + + dst->rgb_range = get_range_for_component_type(format->rgb_type); + dst->a_range = get_range_for_component_type(format->a_type); + for (c = 0; c < 4; ++c) + { + const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; + static const unsigned int component_offsets[4] = {3, 0, 1, 2}; + float *dst_component = &dst->value.x + component_offsets[c]; + + if (format->bits[c]) + { + mask = ~0u >> (32 - format->bits[c]); + + memcpy(&tmp, src + format->shift[c] / 8, + min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8)); + tmp = (tmp >> (format->shift[c] % 8)) & mask; + + switch (dst_ctype) + { + case CTYPE_FLOAT: + if (format->bits[c] == 16) + *dst_component = float_16_to_32(tmp); + else + *dst_component = *(float *)&tmp; + break; + + case CTYPE_INDEX: + *dst_component = (&palette[tmp].peRed)[component_offsets[c]] / 255.0f; + break; + + case CTYPE_LUMA: + case CTYPE_UNORM: + *dst_component = (float)tmp / mask; + break; + + case CTYPE_SNORM: + { + const uint32_t sign_bit = (1u << (format->bits[c] - 1)); + uint32_t tmp_extended = (tmp & sign_bit) ? (tmp | ~(sign_bit - 1)) : tmp; + + /* + * In order to clamp to an even range, we need to ignore + * the maximum negative value. + */ + if (tmp == sign_bit) + tmp_extended |= 1; + + *dst_component = (float)(((int32_t)tmp_extended)) / (sign_bit - 1); + break; + } + + default: + break; + } + } + else if (dst_ctype == CTYPE_LUMA) + { + assert(format->bits[1]); + *dst_component = dst->value.x; + } + else + { + *dst_component = 1.0f; + } + } +} + +/* It doesn't work for components bigger than 32 bits. */ +void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) +{ + DWORD v, mask32; + unsigned int c, i; + + memset(dst, 0, format->bytes_per_pixel); + + for (c = 0; c < 4; ++c) + { + const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; + static const unsigned int component_offsets[4] = {3, 0, 1, 2}; + const float src_component = *(&src->value.x + component_offsets[c]); + const enum range src_range = !c ? src->a_range : src->rgb_range; + + if (!format->bits[c]) + continue; + + mask32 = ~0u >> (32 - format->bits[c]); + + switch (dst_ctype) + { + case CTYPE_FLOAT: + if (format->bits[c] == 16) + v = float_32_to_16(src_component); + else + v = *(DWORD *)&src_component; + break; + + case CTYPE_LUMA: + { + float val = src->value.x * 0.2125f + src->value.y * 0.7154f + src->value.z * 0.0721f; + + if (src_range == RANGE_SNORM) + val = (val + 1.0f) / 2.0f; + + v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; + break; + } + + case CTYPE_UNORM: + { + float val = src_component; + + if (src_range == RANGE_SNORM) + val = (val + 1.0f) / 2.0f; + + v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; + break; + } + + case CTYPE_SNORM: + { + const uint32_t max_value = (1u << (format->bits[c] - 1)) - 1; + float val = src_component; + + if (src_range == RANGE_UNORM) + val = (val * 2.0f) - 1.0f; + + v = d3dx_clamp(val, -1.0f, 1.0f) * max_value + 0.5f; + break; + } + + /* We shouldn't be trying to output to CTYPE_INDEX. */ + case CTYPE_INDEX: + assert(0); + break; + + default: + v = 0; + break; + } + + for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) + { + BYTE mask, byte; + + if (format->shift[c] > i) + { + mask = mask32 << (format->shift[c] - i); + byte = (v << (format->shift[c] - i)) & mask; + } + else + { + mask = mask32 >> (i - format->shift[c]); + byte = (v >> (i - format->shift[c])) & mask; + } + dst[i / 8] |= byte; + } + } +} + +struct d3dx_color_key +{ + uint8_t color_key_min[4]; + uint8_t color_key_max[4]; +}; + +static const char *debug_d3dx_color_key(const struct d3dx_color_key *color_key) +{ + if (!color_key) + return "(null)"; + return wine_dbg_sprintf("(0x%02x->0x%02x)-(0x%02x->0x%02x)-(0x%02x->0x%02x)-(0x%02x->0x%02x)", + color_key->color_key_min[0], color_key->color_key_max[0], + color_key->color_key_min[1], color_key->color_key_max[1], + color_key->color_key_min[2], color_key->color_key_max[2], + color_key->color_key_min[3], color_key->color_key_max[3]); +} + +static void d3dx_init_color_key(const struct pixel_format_desc *src_fmt, uint32_t color_key, + struct d3dx_color_key *color_key_out) +{ + unsigned int i; + + for (i = 0; i < 4; ++i) + { + const enum component_type src_ctype = !i ? src_fmt->a_type : src_fmt->rgb_type; + const uint8_t channel_bits = (src_ctype == CTYPE_LUMA) ? src_fmt->bits[1] : src_fmt->bits[i]; + const uint8_t ck_channel = (color_key >> (24 - (i * 8))) & 0xff; + float slop, channel_conv, unique_values; + + if (!channel_bits) + { + color_key_out->color_key_min[i] = 0x00; + color_key_out->color_key_max[i] = 0xff; + continue; + } + + /* + * If the source format channel can represent all unique channel + * values in the color key, no extra processing is necessary. + */ + if (src_ctype == CTYPE_FLOAT || (src_ctype == CTYPE_SNORM && channel_bits > 8) + || (src_ctype != CTYPE_SNORM && channel_bits >= 8)) + { + color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = ck_channel; + continue; + } + + channel_conv = ck_channel / 255.0f; + if (src_ctype == CTYPE_SNORM) + { + const uint32_t max_value = (1u << (channel_bits - 1)) - 1; + + unique_values = (1u << channel_bits) - 2; + channel_conv = (channel_conv * 2.0f) - 1.0f; + channel_conv = rintf(channel_conv * max_value) / max_value; + channel_conv = (channel_conv + 1.0f) / 2.0f; + } + else + { + unique_values = (1u << channel_bits) - 1; + channel_conv = rintf(channel_conv * unique_values) / unique_values; + } + + channel_conv = channel_conv * 255.0f; + slop = (255.0f - unique_values) / unique_values / 2.0f; + color_key_out->color_key_min[i] = rintf(d3dx_clamp(channel_conv - slop, 0.0f, 255.0f)); + color_key_out->color_key_max[i] = rintf(d3dx_clamp(channel_conv + slop, 0.0f, 255.0f)); + } +} + +/************************************************************ + * copy_pixels + * + * Copies the source buffer to the destination buffer. + * Works for any pixel format. + * The source and the destination must be block-aligned. + */ +static void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, + BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, + const struct pixel_format_desc *format) +{ + 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; + + for (slice = 0; slice < size->depth; slice++) + { + src_addr = src + slice * src_slice_pitch; + dst_addr = dst + slice * dst_slice_pitch; + + for (row = 0; row < row_count; row++) + { + memcpy(dst_addr, src_addr, row_block_count * format->block_byte_count); + src_addr += src_row_pitch; + dst_addr += dst_row_pitch; + } + } +} + +static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format_desc *src_fmt, + uint8_t *dst_ptr, const struct pixel_format_desc *dst_fmt, const PALETTEENTRY *palette, + struct argb_conversion_info *conv_info, const struct d3dx_color_key *color_key, + const struct pixel_format_desc *ck_format, struct argb_conversion_info *ck_conv_info) +{ + unsigned int i; + + if (format_types_match(src_fmt, dst_fmt) && src_fmt->bytes_per_pixel <= 4 && dst_fmt->bytes_per_pixel <= 4) + { + DWORD channels[4]; + DWORD val; + + 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, src_ptr, channels); + ck_pixel = make_argb_color(ck_conv_info, channels); + for (i = 0; i < 4; ++i) + { + const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff; + + if ((ck_channel < color_key->color_key_min[i]) || (ck_channel > color_key->color_key_max[i])) + break; + } + if (i == 4) + val = 0; + } + memcpy(dst_ptr, &val, dst_fmt->bytes_per_pixel); + } + else + { + struct d3dx_color color, tmp; + + format_to_d3dx_color(src_fmt, src_ptr, palette, &color); + tmp = color; + + if (color_key) + { + DWORD ck_pixel = 0; + + format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); + for (i = 0; i < 4; ++i) + { + const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff; + + if ((ck_channel < color_key->color_key_min[i]) || (ck_channel > color_key->color_key_max[i])) + break; + } + if (i == 4) + tmp.value.x = tmp.value.y = tmp.value.z = tmp.value.w = 0.0f; + } + + color = tmp; + format_from_d3dx_color(dst_fmt, &color, dst_ptr); + } +} + +/************************************************************ + * convert_argb_pixels + * + * Copies the source buffer to the destination buffer, performing + * any necessary format conversion and color keying. + * Pixels outsize the source rect are blacked out. + */ +static 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, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key, + const PALETTEENTRY *palette) +{ + /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ + const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; + struct argb_conversion_info conv_info, ck_conv_info; + UINT min_width, min_height, min_depth; + UINT x, y, z; + + TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " + "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %s, palette %p.\n", + src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, + dst_format, debug_d3dx_color_key(color_key), palette); + + init_argb_conversion_info(src_format, dst_format, &conv_info); + + min_width = min(src_size->width, dst_size->width); + min_height = min(src_size->height, dst_size->height); + min_depth = min(src_size->depth, dst_size->depth); + + if (color_key) + init_argb_conversion_info(src_format, ck_format, &ck_conv_info); + + for (z = 0; z < min_depth; z++) { + const BYTE *src_slice_ptr = src + z * src_slice_pitch; + BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; + + for (y = 0; y < min_height; y++) { + const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch; + BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; + + for (x = 0; x < min_width; x++) { + convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, + &conv_info, color_key, ck_format, &ck_conv_info); + + src_ptr += src_format->bytes_per_pixel; + dst_ptr += dst_format->bytes_per_pixel; + } + + if (src_size->width < dst_size->width) /* black out remaining pixels */ + memset(dst_ptr, 0, dst_format->bytes_per_pixel * (dst_size->width - src_size->width)); + } + + if (src_size->height < dst_size->height) /* black out remaining pixels */ + memset(dst + src_size->height * dst_row_pitch, 0, dst_row_pitch * (dst_size->height - src_size->height)); + } + if (src_size->depth < dst_size->depth) /* black out remaining pixels */ + memset(dst + src_size->depth * dst_slice_pitch, 0, dst_slice_pitch * (dst_size->depth - src_size->depth)); +} + +/************************************************************ + * point_filter_argb_pixels + * + * Copies the source buffer to the destination buffer, performing + * any necessary format conversion, color keying and stretching + * using a point filter. + */ +static 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 struct volume *dst_size, const struct pixel_format_desc *dst_format, + const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) +{ + /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ + const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; + struct argb_conversion_info conv_info, ck_conv_info; + UINT x, y, z; + + TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " + "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %s, palette %p.\n", + src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, + dst_format, debug_d3dx_color_key(color_key), palette); + + init_argb_conversion_info(src_format, dst_format, &conv_info); + + if (color_key) + init_argb_conversion_info(src_format, ck_format, &ck_conv_info); + + for (z = 0; z < dst_size->depth; z++) + { + BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; + const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth); + + for (y = 0; y < dst_size->height; y++) + { + BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; + const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height); + + for (x = 0; x < dst_size->width; x++) + { + const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel; + + convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, + &conv_info, color_key, ck_format, &ck_conv_info); + dst_ptr += dst_format->bytes_per_pixel; + } + } + } +} + +static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, + BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, + const struct pixel_format_desc **out_desc) +{ + uint32_t uncompressed_slice_pitch, uncompressed_row_pitch, block_buf_row_pitch, block_width_mask, block_height_mask; + void (*decompress_bcn_block)(const void *src, void *dst, int dst_row_pitch); + const struct pixel_format_desc *uncompressed_desc = NULL; + const struct volume *size = &pixels->size; + BYTE *uncompressed_mem; + uint8_t block_buf[64]; + unsigned int x, y, z; + RECT aligned_rect; + + switch (desc->format) + { + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + decompress_bcn_block = bcdec_bc1; + break; + + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + decompress_bcn_block = bcdec_bc2; + break; + + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + decompress_bcn_block = bcdec_bc3; + break; + + default: + FIXME("Unexpected compressed texture format %u.\n", desc->format); + return E_NOTIMPL; + } + + block_width_mask = desc->block_width - 1; + block_height_mask = desc->block_height - 1; + block_buf_row_pitch = desc->block_width * uncompressed_desc->bytes_per_pixel; + uncompressed_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; + uncompressed_slice_pitch = uncompressed_row_pitch * size->height; + if (!(uncompressed_mem = malloc(size->depth * uncompressed_slice_pitch))) + return E_OUTOFMEMORY; + + /* + * For compressed destination pixels, width/height will represent + * the entire set of compressed blocks our destination rectangle touches. + * If we're only updating a sub-area of any blocks, we need to decompress + * the pixels outside of the sub-area. + */ + if (is_dst) + { + SetRect(&aligned_rect, 0, 0, size->width, size->height); + + /* + * If our destination covers the entire set of blocks, no + * decompression needs to be done, just return the allocated memory. + */ + if (EqualRect(&aligned_rect, &pixels->unaligned_rect)) + goto exit; + } + /* + * For compressed source pixels, width/height will represent the size of + * the unaligned rectangle. I.e, if we have an 8x8 source with an + * unaligned rect of (2,2)-(6,6) our width/height will be 4. + */ + else + { + SetRect(&aligned_rect, 0, 0, (pixels->unaligned_rect.right + block_width_mask) & ~block_width_mask, + (pixels->unaligned_rect.bottom + block_height_mask) & ~block_height_mask); + } + + TRACE("Decompressing pixels.\n"); + for (z = 0; z < size->depth; ++z) + { + const uint8_t *src_slice = &((const uint8_t *)pixels->data)[z * pixels->slice_pitch]; + uint8_t *dst_slice = &uncompressed_mem[z * uncompressed_slice_pitch]; + + for (y = 0; y < aligned_rect.bottom; y += desc->block_height) + { + const uint8_t *src_ptr = &src_slice[(y / desc->block_height) * pixels->row_pitch]; + + for (x = 0; x < aligned_rect.right; x += desc->block_width) + { + struct volume dst_block_size; + RECT src_rect, dst_rect; + uint8_t *dst_ptr; + + SetRect(&src_rect, x, y, x + desc->block_width, y + desc->block_height); + IntersectRect(&src_rect, &src_rect, &pixels->unaligned_rect); + dst_rect = src_rect; + OffsetRect(&dst_rect, -pixels->unaligned_rect.left, -pixels->unaligned_rect.top); + + set_volume_struct(&dst_block_size, dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top, 1); + dst_ptr = &dst_slice[(dst_rect.top * uncompressed_row_pitch)]; + dst_ptr += dst_rect.left * uncompressed_desc->bytes_per_pixel; + + if (dst_block_size.width != desc->block_width || dst_block_size.height != desc->block_height) + { + if (!is_dst) + { + unsigned int block_buf_offset; + + decompress_bcn_block(src_ptr, block_buf, block_buf_row_pitch); + block_buf_offset = (src_rect.top - y) * block_buf_row_pitch; + block_buf_offset += uncompressed_desc->bytes_per_pixel * (src_rect.left - x); + copy_pixels(&block_buf[block_buf_offset], block_buf_row_pitch, 0, dst_ptr, + uncompressed_row_pitch, 0, &dst_block_size, uncompressed_desc); + } + /* + * If this is the destination, we can just copy the whole + * block. It will be partially overwritten later. + */ + else + { + dst_ptr = &dst_slice[y * uncompressed_row_pitch + x * uncompressed_desc->bytes_per_pixel]; + decompress_bcn_block(src_ptr, dst_ptr, uncompressed_row_pitch); + } + + } + /* Full block copy. */ + else if (!is_dst) + { + decompress_bcn_block(src_ptr, dst_ptr, uncompressed_row_pitch); + } + src_ptr += desc->block_byte_count; + } + } + } + +exit: + *out_memory = uncompressed_mem; + *out_row_pitch = uncompressed_row_pitch; + *out_slice_pitch = uncompressed_slice_pitch; + *out_desc = uncompressed_desc; + + return S_OK; +} + +static HRESULT d3dx_pixels_unpack_index(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, + void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, const struct pixel_format_desc **out_desc) +{ + uint32_t x, y, z, unpacked_slice_pitch, unpacked_row_pitch; + const struct pixel_format_desc *unpacked_desc = NULL; + const struct volume *size = &pixels->size; + uint8_t *unpacked_mem; + uint8_t mask, shift; + + switch (desc->format) + { + case D3DX_PIXEL_FORMAT_P1_UINT: + case D3DX_PIXEL_FORMAT_P2_UINT: + case D3DX_PIXEL_FORMAT_P4_UINT: + unpacked_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_P8_UINT); + break; + + default: + FIXME("Unexpected format %u.\n", desc->format); + return E_NOTIMPL; + } + + unpacked_row_pitch = size->width * unpacked_desc->bytes_per_pixel; + unpacked_slice_pitch = unpacked_row_pitch * size->height; + if (!(unpacked_mem = malloc(size->depth * unpacked_slice_pitch))) + return E_OUTOFMEMORY; + + shift = 8 / desc->block_width; + mask = (1u << shift) - 1; + + TRACE("Unpacking pixels.\n"); + for (z = 0; z < size->depth; ++z) + { + const uint8_t *slice_data = (const uint8_t *)pixels->data + (pixels->slice_pitch * z); + + for (y = 0; y < size->height; ++y) + { + uint8_t *ptr = &unpacked_mem[(z * unpacked_slice_pitch) + (y * unpacked_row_pitch)]; + const uint8_t *row_data = slice_data + (pixels->row_pitch * y); + + for (x = 0; x < size->width; x += desc->block_width) + { + const uint8_t packed_data = *row_data; + unsigned int i; + + for (i = 0; i < desc->block_width; ++i) + { + const uint8_t cur_shift = ((desc->block_width - 1) - i) * shift; + + if (x + i >= size->width) + break; + ptr[i] = (packed_data >> cur_shift) & mask; + } + ptr += unpacked_desc->bytes_per_pixel * desc->block_width; + row_data++; + } + } + } + + *out_memory = unpacked_mem; + *out_row_pitch = unpacked_row_pitch; + *out_slice_pitch = unpacked_slice_pitch; + *out_desc = unpacked_desc; + + return S_OK; +} + +static void d3dx_compress_block(enum d3dx_pixel_format_id fmt, uint8_t *block_buf, void *dst_buf) +{ + switch (fmt) + { + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + stb_compress_dxt_block(dst_buf, block_buf, FALSE, 0); + break; + + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + { + uint8_t *dst_data_offset = dst_buf; + unsigned int y; + + /* STB doesn't do DXT2/DXT3, we'll do the alpha part ourselves. */ + for (y = 0; y < 4; ++y) + { + uint8_t *tmp_row = &block_buf[y * 4 * 4]; + + dst_data_offset[0] = (tmp_row[7] & 0xf0); + dst_data_offset[0] |= (tmp_row[3] >> 4); + dst_data_offset[1] = (tmp_row[15] & 0xf0); + dst_data_offset[1] |= (tmp_row[11] >> 4); + + /* + * Set all alpha values to 0xff so they aren't considered during + * compression. This modifies the source data being passed in. + */ + tmp_row[3] = tmp_row[7] = tmp_row[11] = tmp_row[15] = 0xff; + dst_data_offset += 2; + } + stb_compress_dxt_block(dst_data_offset, block_buf, FALSE, 0); + break; + } + + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + stb_compress_dxt_block(dst_buf, block_buf, TRUE, 0); + break; + + default: + assert(0); + break; + } +} + +/* + * Source data passed into this function is potentially modified (currently + * only in the case of DXT2/DXT3). As of now we only pass temporary buffers + * into this function, but this should be taken to account if used elsewhere + * outside of d3dx_load_pixels_from_pixels() in the future. + */ +static HRESULT d3dx_pixels_compress(struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc) +{ + unsigned int x, y, z, block_buf_row_pitch; + uint8_t block_buf[64]; + + switch (dst_desc->format) + { + case D3DX_PIXEL_FORMAT_DXT1_UNORM: + case D3DX_PIXEL_FORMAT_DXT2_UNORM: + case D3DX_PIXEL_FORMAT_DXT3_UNORM: + case D3DX_PIXEL_FORMAT_DXT4_UNORM: + case D3DX_PIXEL_FORMAT_DXT5_UNORM: + assert(src_desc->format == D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); + break; + + default: + FIXME("Unexpected compressed texture format %u.\n", dst_desc->format); + return E_NOTIMPL; + } + + TRACE("Compressing pixels.\n"); + block_buf_row_pitch = src_desc->bytes_per_pixel * dst_desc->block_width; + for (z = 0; z < src_pixels->size.depth; ++z) + { + const uint8_t *src_slice = &((const uint8_t *)src_pixels->data)[z * src_pixels->slice_pitch]; + uint8_t *dst_slice = &((uint8_t *)dst_pixels->data)[z * dst_pixels->slice_pitch]; + + for (y = 0; y < src_pixels->size.height; y += dst_desc->block_height) + { + const unsigned int tmp_src_height = min(dst_desc->block_height, src_pixels->size.height - y); + uint8_t *dst_ptr = &dst_slice[(y / dst_desc->block_height) * dst_pixels->row_pitch]; + const uint8_t *src_ptr = &src_slice[y * src_pixels->row_pitch]; + + for (x = 0; x < src_pixels->size.width; x += dst_desc->block_width) + { + const unsigned int tmp_src_width = min(dst_desc->block_width, src_pixels->size.width - x); + struct volume block_buf_size = { tmp_src_width, tmp_src_height, 1 }; + + if (tmp_src_width != dst_desc->block_width || tmp_src_height != dst_desc->block_height) + memset(block_buf, 0, sizeof(block_buf)); + copy_pixels(src_ptr, src_pixels->row_pitch, src_pixels->slice_pitch, block_buf, block_buf_row_pitch, 0, + &block_buf_size, src_desc); + d3dx_compress_block(dst_desc->format, block_buf, dst_ptr); + src_ptr += (src_desc->bytes_per_pixel * dst_desc->block_width); + dst_ptr += dst_desc->block_byte_count; + } + } + } + + return S_OK; +} + +HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, + const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, + uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels) +{ + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(format); + const BYTE *ptr = data; + RECT unaligned_rect; + + memset(pixels, 0, sizeof(*pixels)); + if (is_unknown_format(fmt_desc)) + { + FIXME("Unsupported format %#x.\n", format); + return E_NOTIMPL; + } + + ptr += front * slice_pitch; + ptr += (top / fmt_desc->block_height) * row_pitch; + ptr += (left / fmt_desc->block_width) * fmt_desc->block_byte_count; + + if (is_compressed_format(fmt_desc)) + { + uint32_t left_aligned, top_aligned; + + top_aligned = top & ~(fmt_desc->block_height - 1); + left_aligned = left & ~(fmt_desc->block_width - 1); + SetRect(&unaligned_rect, left, top, right, bottom); + OffsetRect(&unaligned_rect, -left_aligned, -top_aligned); + } + else + { + SetRect(&unaligned_rect, 0, 0, (right - left), (bottom - top)); + } + + if (!slice_pitch) + slice_pitch = row_pitch * (bottom - top); + set_d3dx_pixels(pixels, ptr, row_pitch, slice_pitch, palette, (right - left), (bottom - top), (back - front), + &unaligned_rect); + + return S_OK; +} + +static const char *debug_d3dx_pixels(struct d3dx_pixels *pixels) +{ + if (!pixels) + return "(null)"; + return wine_dbg_sprintf("(data %p, row_pitch %d, slice_pitch %d, palette %p, width %d, height %d, depth %d, " + "unaligned_rect %s)", pixels->data, pixels->row_pitch, pixels->slice_pitch, pixels->palette, + pixels->size.width, pixels->size.height, pixels->size.depth, wine_dbgstr_rect(&pixels->unaligned_rect)); +} + +HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) +{ + struct volume src_size, dst_size, dst_size_aligned; + const struct d3dx_color_key *d3dx_ck = NULL; + struct d3dx_color_key d3dx_color_key; + HRESULT hr = S_OK; + + TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", + debug_d3dx_pixels(dst_pixels), dst_desc, debug_d3dx_pixels(src_pixels), src_desc, + filter_flags, color_key); + + if (is_compressed_format(src_desc)) + set_volume_struct(&src_size, (src_pixels->unaligned_rect.right - src_pixels->unaligned_rect.left), + (src_pixels->unaligned_rect.bottom - src_pixels->unaligned_rect.top), src_pixels->size.depth); + else + src_size = src_pixels->size; + + dst_size_aligned = dst_pixels->size; + if (is_compressed_format(dst_desc)) + set_volume_struct(&dst_size, (dst_pixels->unaligned_rect.right - dst_pixels->unaligned_rect.left), + (dst_pixels->unaligned_rect.bottom - dst_pixels->unaligned_rect.top), dst_pixels->size.depth); + else + dst_size = dst_size_aligned; + + /* Everything matches, simply copy the pixels. */ + if (src_desc->format == dst_desc->format + && (dst_size.width == src_size.width && !(dst_size.width % dst_desc->block_width)) + && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) + && (dst_size.depth == src_size.depth) + && color_key == 0 + && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) + && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) + && !(dst_pixels->unaligned_rect.left & (dst_desc->block_width - 1)) + && !(dst_pixels->unaligned_rect.top & (dst_desc->block_height - 1))) + { + TRACE("Simple copy.\n"); + copy_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, (void *)dst_pixels->data, + dst_pixels->row_pitch, dst_pixels->slice_pitch, &src_size, src_desc); + return S_OK; + } + + /* Stretching or format conversion. */ + if (!is_conversion_from_supported(src_desc) + || !is_conversion_to_supported(dst_desc)) + { + FIXME("Unsupported format conversion %#x -> %#x.\n", src_desc->format, dst_desc->format); + return E_NOTIMPL; + } + + if (is_index_format(src_desc) && (src_desc->block_width > 1)) + { + uint32_t unpacked_row_pitch, unpacked_slice_pitch; + const struct pixel_format_desc *unpacked_desc; + void *unpacked_mem = NULL; + + hr = d3dx_pixels_unpack_index(src_pixels, src_desc, &unpacked_mem, &unpacked_row_pitch, + &unpacked_slice_pitch, &unpacked_desc); + if (SUCCEEDED(hr)) + { + struct d3dx_pixels unpacked_pixels; + + d3dx_pixels_init(unpacked_mem, unpacked_row_pitch, unpacked_slice_pitch, src_pixels->palette, + unpacked_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, + 0, src_pixels->size.depth, &unpacked_pixels); + + hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &unpacked_pixels, unpacked_desc, + filter_flags, color_key); + } + free(unpacked_mem); + goto exit; + } + + /* + * If the source is a compressed image, we need to decompress it first + * before doing any modifications. + */ + if (is_compressed_format(src_desc)) + { + uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; + const struct pixel_format_desc *uncompressed_desc; + void *uncompressed_mem = NULL; + + hr = d3dx_pixels_decompress(src_pixels, src_desc, FALSE, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_slice_pitch, &uncompressed_desc); + if (SUCCEEDED(hr)) + { + struct d3dx_pixels uncompressed_pixels; + + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, + 0, src_pixels->size.depth, &uncompressed_pixels); + + if (sizeof(void *) == 4 && color_key) + { + TRACE("Clearing color key value on compressed source pixels.\n"); + color_key = 0; + } + hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, + filter_flags, color_key); + } + free(uncompressed_mem); + goto exit; + } + + /* Same as the above, need to decompress the destination prior to modifying. */ + if (is_compressed_format(dst_desc)) + { + uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; + const struct pixel_format_desc *uncompressed_desc; + struct d3dx_pixels uncompressed_pixels; + void *uncompressed_mem = NULL; + + hr = d3dx_pixels_decompress(dst_pixels, dst_desc, TRUE, &uncompressed_mem, &uncompressed_row_pitch, + &uncompressed_slice_pitch, &uncompressed_desc); + if (FAILED(hr)) + goto exit; + + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, dst_pixels->unaligned_rect.left, dst_pixels->unaligned_rect.top, + dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, dst_pixels->size.depth, + &uncompressed_pixels); + + hr = d3dx_load_pixels_from_pixels(&uncompressed_pixels, uncompressed_desc, src_pixels, src_desc, filter_flags, + color_key); + if (SUCCEEDED(hr)) + { + d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, + uncompressed_desc->format, 0, 0, dst_size_aligned.width, dst_size_aligned.height, 0, + dst_pixels->size.depth, &uncompressed_pixels); + + hr = d3dx_pixels_compress(&uncompressed_pixels, uncompressed_desc, dst_pixels, dst_desc); + if (FAILED(hr)) + WARN("Failed to compress pixels, hr %#lx.\n", hr); + } + free(uncompressed_mem); + goto exit; + } + + if (color_key) + { + d3dx_init_color_key(src_desc, color_key, &d3dx_color_key); + d3dx_ck = &d3dx_color_key; + } + + if ((filter_flags & 0xf) == D3DX_FILTER_NONE) + { + convert_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, + (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, dst_desc, + d3dx_ck, src_pixels->palette); + } + else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ + { + if ((filter_flags & 0xf) != D3DX_FILTER_POINT) + FIXME("Unhandled filter %#x.\n", filter_flags); + + /* Always apply a point filter until D3DX_FILTER_LINEAR, + * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ + point_filter_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, + src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, + dst_desc, d3dx_ck, src_pixels->palette); + } + +exit: + if (FAILED(hr)) + WARN("Failed to load pixels, hr %#lx.\n", hr); + return hr; +} + +void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, + const struct pixel_format_desc *fmt_desc, RECT *aligned_rect) +{ + SetRect(aligned_rect, left, top, right, bottom); + if (aligned_rect->left & (fmt_desc->block_width - 1)) + aligned_rect->left = aligned_rect->left & ~(fmt_desc->block_width - 1); + if (aligned_rect->top & (fmt_desc->block_height - 1)) + aligned_rect->top = aligned_rect->top & ~(fmt_desc->block_height - 1); + if (aligned_rect->right & (fmt_desc->block_width - 1) && aligned_rect->right != width) + aligned_rect->right = min((aligned_rect->right + fmt_desc->block_width - 1) + & ~(fmt_desc->block_width - 1), width); + if (aligned_rect->bottom & (fmt_desc->block_height - 1) && aligned_rect->bottom != height) + aligned_rect->bottom = min((aligned_rect->bottom + fmt_desc->block_height - 1) + & ~(fmt_desc->block_height - 1), height); +} diff --git a/dlls/d3dx9_36/d3dx_helpers.h b/dlls/d3dx9_36/d3dx_helpers.h new file mode 100644 index 00000000000..fb139ed8cb9 --- /dev/null +++ b/dlls/d3dx9_36/d3dx_helpers.h @@ -0,0 +1,384 @@ +/* + * Copyright 2025 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef __WINE_D3DX_HELPERS_H +#define __WINE_D3DX_HELPERS_H + +#include <stdint.h> +#include "windef.h" /* For RECT. */ +#include "wingdi.h" /* For PALETTEENTRY. */ + +#if D3DX_D3D_VERSION == 9 +#define COBJMACROS +#include "d3dx9.h" +#endif /* D3DX_D3D_VERSION == 9 */ + +#define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256) + +/* dds_header.flags */ +#define DDS_CAPS 0x1 +#define DDS_HEIGHT 0x2 +#define DDS_WIDTH 0x4 +#define DDS_PITCH 0x8 +#define DDS_PIXELFORMAT 0x1000 +#define DDS_MIPMAPCOUNT 0x20000 +#define DDS_LINEARSIZE 0x80000 +#define DDS_DEPTH 0x800000 + +/* dds_header.caps */ +#define DDSCAPS_ALPHA 0x2 +#define DDS_CAPS_COMPLEX 0x8 +#define DDSCAPS_PALETTE 0x100 +#define DDS_CAPS_TEXTURE 0x1000 +#define DDS_CAPS_MIPMAP 0x400000 + +/* dds_header.caps2 */ +#define DDS_CAPS2_CUBEMAP 0x200 +#define DDS_CAPS2_CUBEMAP_POSITIVEX 0x400 +#define DDS_CAPS2_CUBEMAP_NEGATIVEX 0x800 +#define DDS_CAPS2_CUBEMAP_POSITIVEY 0x1000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEY 0x2000 +#define DDS_CAPS2_CUBEMAP_POSITIVEZ 0x4000 +#define DDS_CAPS2_CUBEMAP_NEGATIVEZ 0x8000 +#define DDS_CAPS2_CUBEMAP_ALL_FACES ( DDS_CAPS2_CUBEMAP_POSITIVEX | DDS_CAPS2_CUBEMAP_NEGATIVEX \ + | DDS_CAPS2_CUBEMAP_POSITIVEY | DDS_CAPS2_CUBEMAP_NEGATIVEY \ + | DDS_CAPS2_CUBEMAP_POSITIVEZ | DDS_CAPS2_CUBEMAP_NEGATIVEZ ) +#define DDS_CAPS2_VOLUME 0x200000 + +/* dds_pixel_format.flags */ +#define DDS_PF_ALPHA 0x1 +#define DDS_PF_ALPHA_ONLY 0x2 +#define DDS_PF_FOURCC 0x4 +#define DDS_PF_INDEXED 0x20 +#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 +{ + DWORD size; + DWORD flags; + DWORD fourcc; + DWORD bpp; + DWORD rmask; + DWORD gmask; + DWORD bmask; + DWORD amask; +}; + +struct dds_header +{ + DWORD signature; + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitch_or_linear_size; + DWORD depth; + DWORD miplevels; + DWORD reserved[11]; + struct dds_pixel_format pixel_format; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +}; + +struct vec4 +{ + float x, y, z, w; +}; + +enum range { + RANGE_FULL = 0, + RANGE_UNORM = 1, + RANGE_SNORM = 2, +}; + +struct d3dx_color +{ + struct vec4 value; + enum range rgb_range; + enum range a_range; +}; + +static inline void set_d3dx_color(struct d3dx_color *color, const struct vec4 *value, enum range rgb_range, + enum range a_range) +{ + color->value = *value; + color->rgb_range = rgb_range; + color->a_range = a_range; +} + +struct volume +{ + UINT width; + UINT height; + UINT depth; +}; + +static inline void set_volume_struct(struct volume *volume, uint32_t width, uint32_t height, uint32_t depth) +{ + volume->width = width; + volume->height = height; + volume->depth = depth; +} + +enum d3dx_image_file_format +{ + D3DX_IMAGE_FILE_FORMAT_BMP = 0, + D3DX_IMAGE_FILE_FORMAT_JPG = 1, + D3DX_IMAGE_FILE_FORMAT_TGA = 2, + D3DX_IMAGE_FILE_FORMAT_PNG = 3, + D3DX_IMAGE_FILE_FORMAT_DDS = 4, + D3DX_IMAGE_FILE_FORMAT_PPM = 5, + D3DX_IMAGE_FILE_FORMAT_DIB = 6, + D3DX_IMAGE_FILE_FORMAT_HDR = 7, + D3DX_IMAGE_FILE_FORMAT_PFM = 8, + D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD = 0x7fffffff +}; + +enum d3dx_resource_type +{ + D3DX_RESOURCE_TYPE_TEXTURE_2D, + D3DX_RESOURCE_TYPE_TEXTURE_3D, + D3DX_RESOURCE_TYPE_CUBE_TEXTURE, + D3DX_RESOURCE_TYPE_COUNT, +}; + +/* These values act as indexes into the pixel_format_desc table. */ +enum d3dx_pixel_format_id +{ + D3DX_PIXEL_FORMAT_B8G8R8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, + D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, + D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, + D3DX_PIXEL_FORMAT_B5G6R5_UNORM, + D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, + D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3_UNORM, + D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, + D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, + D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, + D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, + D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, + D3DX_PIXEL_FORMAT_R16G16B16_UNORM, + D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, + D3DX_PIXEL_FORMAT_R16G16_UNORM, + D3DX_PIXEL_FORMAT_A8_UNORM, + D3DX_PIXEL_FORMAT_L8A8_UNORM, + D3DX_PIXEL_FORMAT_L4A4_UNORM, + D3DX_PIXEL_FORMAT_L8_UNORM, + D3DX_PIXEL_FORMAT_L16_UNORM, + D3DX_PIXEL_FORMAT_DXT1_UNORM, + D3DX_PIXEL_FORMAT_DXT2_UNORM, + D3DX_PIXEL_FORMAT_DXT3_UNORM, + D3DX_PIXEL_FORMAT_DXT4_UNORM, + D3DX_PIXEL_FORMAT_DXT5_UNORM, + D3DX_PIXEL_FORMAT_R16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16_FLOAT, + D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, + D3DX_PIXEL_FORMAT_R32_FLOAT, + D3DX_PIXEL_FORMAT_R32G32_FLOAT, + D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, + D3DX_PIXEL_FORMAT_P1_UINT, + D3DX_PIXEL_FORMAT_P2_UINT, + D3DX_PIXEL_FORMAT_P4_UINT, + D3DX_PIXEL_FORMAT_P8_UINT, + D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, + D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, + D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, + D3DX_PIXEL_FORMAT_U8V8_SNORM, + D3DX_PIXEL_FORMAT_U16V16_SNORM, + D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, + D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, + D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, + D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, + D3DX_PIXEL_FORMAT_UYVY, + D3DX_PIXEL_FORMAT_YUY2, + D3DX_PIXEL_FORMAT_COUNT, +}; + +/* for internal use */ +enum component_type +{ + CTYPE_EMPTY, + CTYPE_UNORM, + CTYPE_SNORM, + CTYPE_FLOAT, + CTYPE_LUMA, + CTYPE_INDEX, +}; + +enum format_flag +{ + FMT_FLAG_DXT = 0x01, + FMT_FLAG_PACKED = 0x02, + /* Internal only format, has no exact D3DFORMAT equivalent. */ + FMT_FLAG_INTERNAL = 0x04, +}; + +struct pixel_format_desc { + enum d3dx_pixel_format_id format; + BYTE bits[4]; + BYTE shift[4]; + UINT bytes_per_pixel; + UINT block_width; + UINT block_height; + UINT block_byte_count; + enum component_type a_type; + enum component_type rgb_type; + uint32_t flags; +}; + +struct d3dx_pixels +{ + const void *data; + uint32_t row_pitch; + uint32_t slice_pitch; + const PALETTEENTRY *palette; + + struct volume size; + RECT unaligned_rect; +}; + +static inline void set_d3dx_pixels(struct d3dx_pixels *pixels, const void *data, uint32_t row_pitch, + uint32_t slice_pitch, const PALETTEENTRY *palette, uint32_t width, uint32_t height, uint32_t depth, + const RECT *unaligned_rect) +{ + pixels->data = data; + pixels->row_pitch = row_pitch; + pixels->slice_pitch = slice_pitch; + pixels->palette = palette; + set_volume_struct(&pixels->size, width, height, depth); + pixels->unaligned_rect = *unaligned_rect; +} + +#define D3DX_IMAGE_INFO_ONLY 1 +struct d3dx_image +{ + enum d3dx_resource_type resource_type; + enum d3dx_pixel_format_id format; + + struct volume size; + uint32_t mip_levels; + uint32_t layer_count; + + BYTE *pixels; + PALETTEENTRY *palette; + uint32_t layer_pitch; + + /* + * image_buf and image_palette are pointers to allocated memory used to store + * image data. If they are non-NULL, they need to be freed when no longer + * in use. + */ + void *image_buf; + PALETTEENTRY *image_palette; + + enum d3dx_image_file_format image_file_format; +}; + +HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, + uint32_t starting_mip_level, uint32_t flags); +void d3dx_image_cleanup(struct d3dx_image *image); +HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, + struct d3dx_pixels *pixels); + +static inline BOOL is_unknown_format(const struct pixel_format_desc *format) +{ + return (format->format == D3DX_PIXEL_FORMAT_COUNT); +} + +static inline BOOL is_index_format(const struct pixel_format_desc *format) +{ + return (format->a_type == CTYPE_INDEX || format->rgb_type == CTYPE_INDEX); +} + +static inline BOOL is_compressed_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_DXT); +} + +static inline BOOL is_packed_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_PACKED); +} + +static inline BOOL format_types_match(const struct pixel_format_desc *src, const struct pixel_format_desc *dst) +{ + if ((src->a_type && dst->a_type) && (src->a_type != dst->a_type)) + return FALSE; + + if ((src->rgb_type && dst->rgb_type) && (src->rgb_type != dst->rgb_type)) + return FALSE; + + if (src->flags != dst->flags) + return FALSE; + + return (src->rgb_type == dst->rgb_type || src->a_type == dst->a_type); +} + +static inline BOOL is_internal_format(const struct pixel_format_desc *format) +{ + return !!(format->flags & FMT_FLAG_INTERNAL); +} + +static inline BOOL is_conversion_from_supported(const struct pixel_format_desc *format) +{ + return !is_packed_format(format) && !is_unknown_format(format); +} + +static inline BOOL is_conversion_to_supported(const struct pixel_format_desc *format) +{ + return !is_index_format(format) && !is_packed_format(format) && !is_unknown_format(format); +} + +const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format); + +void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, + struct d3dx_color *dst); +void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst); + +uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, + uint32_t depth, uint32_t mip_levels); +HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, + enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels); +HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, + enum d3dx_image_file_format file_format, ID3DXBuffer **dst_buffer); +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format); +HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, + const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, + uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels); +HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, + const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, + const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key); +void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, + const struct pixel_format_desc *fmt_desc, RECT *aligned_rect); + +unsigned short float_32_to_16(const float in); +float float_16_to_32(const unsigned short in); + +/* debug helpers */ +const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format); +#endif /* __WINE_D3DX_HELPERS_H */ diff --git a/dlls/d3dx9_36/math.c b/dlls/d3dx9_36/math.c index 92eb8f68f14..ac384213e29 100644 --- a/dlls/d3dx9_36/math.c +++ b/dlls/d3dx9_36/math.c @@ -2099,91 +2099,6 @@ D3DXVECTOR4* WINAPI D3DXVec4TransformArray(D3DXVECTOR4* out, UINT outstride, con return out; }
-unsigned short float_32_to_16(const float in) -{ - int exp = 0, origexp; - float tmp = fabsf(in); - int sign = (copysignf(1, in) < 0); - unsigned int mantissa; - unsigned short ret; - - /* Deal with special numbers */ - if (isinf(in)) return (sign ? 0xffff : 0x7fff); - if (isnan(in)) return (sign ? 0xffff : 0x7fff); - if (in == 0.0f) return (sign ? 0x8000 : 0x0000); - - if (tmp < (float)(1u << 10)) - { - do - { - tmp *= 2.0f; - exp--; - } while (tmp < (float)(1u << 10)); - } - else if (tmp >= (float)(1u << 11)) - { - do - { - tmp /= 2.0f; - exp++; - } while (tmp >= (float)(1u << 11)); - } - - exp += 10; /* Normalize the mantissa */ - exp += 15; /* Exponent is encoded with excess 15 */ - - origexp = exp; - - mantissa = (unsigned int) tmp; - if ((tmp - mantissa == 0.5f && mantissa % 2 == 1) || /* round half to even */ - (tmp - mantissa > 0.5f)) - { - mantissa++; /* round to nearest, away from zero */ - } - if (mantissa == 2048) - { - mantissa = 1024; - exp++; - } - - if (exp > 31) - { - /* too big */ - ret = 0x7fff; /* INF */ - } - else if (exp <= 0) - { - unsigned int rounding = 0; - - /* Denormalized half float */ - - /* return 0x0000 (=0.0) for numbers too small to represent in half floats */ - if (exp < -11) - return (sign ? 0x8000 : 0x0000); - - exp = origexp; - - /* the 13 extra bits from single precision are used for rounding */ - mantissa = (unsigned int)(tmp * (1u << 13)); - mantissa >>= 1 - exp; /* denormalize */ - - mantissa -= ~(mantissa >> 13) & 1; /* round half to even */ - /* remove 13 least significant bits to get half float precision */ - mantissa >>= 12; - rounding = mantissa & 1; - mantissa >>= 1; - - ret = mantissa + rounding; - } - else - { - ret = (exp << 10) | (mantissa & 0x3ff); - } - - ret |= ((sign ? 1 : 0) << 15); /* Add the sign */ - return ret; -} - D3DXFLOAT16 *WINAPI D3DXFloat32To16Array(D3DXFLOAT16 *pout, const FLOAT *pin, UINT n) { unsigned int i; @@ -2198,26 +2113,6 @@ D3DXFLOAT16 *WINAPI D3DXFloat32To16Array(D3DXFLOAT16 *pout, const FLOAT *pin, UI return pout; }
-/* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a - * regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */ -float float_16_to_32(const unsigned short in) -{ - const unsigned short s = (in & 0x8000); - const unsigned short e = (in & 0x7C00) >> 10; - const unsigned short m = in & 0x3FF; - const float sgn = (s ? -1.0f : 1.0f); - - if (e == 0) - { - if (m == 0) return sgn * 0.0f; /* +0.0 or -0.0 */ - else return sgn * powf(2, -14.0f) * (m / 1024.0f); - } - else - { - return sgn * powf(2, e - 15.0f) * (1.0f + (m / 1024.0f)); - } -} - FLOAT *WINAPI D3DXFloat16To32Array(FLOAT *pout, const D3DXFLOAT16 *pin, UINT n) { unsigned int i; diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index b256ae14752..3780f2099c4 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -21,96 +21,10 @@
#include "d3dx9_private.h"
-#include "initguid.h" -#include "ole2.h" -#include "wincodec.h" - -#define BCDEC_IMPLEMENTATION -#define BCDEC_STATIC -#include "bcdec.h" -#define STB_DXT_IMPLEMENTATION -#define STB_DXT_STATIC -#include "stb_dxt.h" #include <assert.h>
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
-HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); - -static const struct -{ - const GUID *wic_guid; - enum d3dx_pixel_format_id d3dx_pixel_format; -} wic_pixel_formats[] = -{ - { &GUID_WICPixelFormat8bppIndexed, D3DX_PIXEL_FORMAT_P8_UINT }, - { &GUID_WICPixelFormat1bppIndexed, D3DX_PIXEL_FORMAT_P1_UINT }, - { &GUID_WICPixelFormat2bppIndexed, D3DX_PIXEL_FORMAT_P2_UINT }, - { &GUID_WICPixelFormat4bppIndexed, D3DX_PIXEL_FORMAT_P4_UINT }, - { &GUID_WICPixelFormat8bppGray, D3DX_PIXEL_FORMAT_L8_UNORM }, - { &GUID_WICPixelFormat16bppBGR555, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, - { &GUID_WICPixelFormat16bppBGR565, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, - { &GUID_WICPixelFormat24bppBGR, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, - { &GUID_WICPixelFormat32bppBGR, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, - { &GUID_WICPixelFormat32bppBGRA, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, - { &GUID_WICPixelFormat48bppRGB, D3DX_PIXEL_FORMAT_R16G16B16_UNORM }, - { &GUID_WICPixelFormat64bppRGBA, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, -}; - -static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_wic_pixel_format(const GUID *guid) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) - { - if (IsEqualGUID(wic_pixel_formats[i].wic_guid, guid)) - return wic_pixel_formats[i].d3dx_pixel_format; - } - - return D3DX_PIXEL_FORMAT_COUNT; - -} - -static const GUID *wic_guid_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id d3dx_pixel_format) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); i++) - { - if (wic_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) - return wic_pixel_formats[i].wic_guid; - } - - return NULL; -} - -#define TGA_IMAGETYPE_COLORMAPPED 1 -#define TGA_IMAGETYPE_TRUECOLOR 2 -#define TGA_IMAGETYPE_GRAYSCALE 3 -#define TGA_IMAGETYPE_MASK 0x07 -#define TGA_IMAGETYPE_RLE 8 - -#define TGA_IMAGE_RIGHTTOLEFT 0x10 -#define TGA_IMAGE_TOPTOBOTTOM 0x20 - -#pragma pack(push,1) -struct tga_header -{ - uint8_t id_length; - uint8_t color_map_type; - uint8_t image_type; - uint16_t color_map_firstentry; - uint16_t color_map_length; - uint8_t color_map_entrysize; - uint16_t xorigin; - uint16_t yorigin; - uint16_t width; - uint16_t height; - uint8_t depth; - uint8_t image_descriptor; -}; -#pragma pack(pop) - HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLOCKED_RECT *lock, IDirect3DSurface9 **temp_surface, BOOL write) { @@ -205,3057 +119,428 @@ HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, return hr; }
-static const struct -{ - struct dds_pixel_format dds_pixel_format; - enum d3dx_pixel_format_id d3dx_pixel_format; -} dds_pixel_formats[] = -{ - /* DDS_PF_FOURCC. */ - { { 32, DDS_PF_FOURCC, MAKEFOURCC('U','Y','V','Y') }, D3DX_PIXEL_FORMAT_UYVY }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('Y','U','Y','2') }, D3DX_PIXEL_FORMAT_YUY2 }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('R','G','B','G') }, D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('G','R','G','B') }, D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','1') }, D3DX_PIXEL_FORMAT_DXT1_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','2') }, D3DX_PIXEL_FORMAT_DXT2_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','3') }, D3DX_PIXEL_FORMAT_DXT3_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','4') }, D3DX_PIXEL_FORMAT_DXT4_UNORM }, - { { 32, DDS_PF_FOURCC, MAKEFOURCC('D','X','T','5') }, D3DX_PIXEL_FORMAT_DXT5_UNORM }, - /* These aren't actually fourcc values, they're just D3DFMT values. */ - { { 32, DDS_PF_FOURCC, 0x24 }, D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM }, - { { 32, DDS_PF_FOURCC, 0x6e }, D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM }, - { { 32, DDS_PF_FOURCC, 0x6f }, D3DX_PIXEL_FORMAT_R16_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x70 }, D3DX_PIXEL_FORMAT_R16G16_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x71 }, D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x72 }, D3DX_PIXEL_FORMAT_R32_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x73 }, D3DX_PIXEL_FORMAT_R32G32_FLOAT }, - { { 32, DDS_PF_FOURCC, 0x74 }, D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT }, - /* DDS_PF_RGB. */ - { { 32, DDS_PF_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 }, D3DX_PIXEL_FORMAT_B2G3R3_UNORM }, - { { 32, DDS_PF_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G6R5_UNORM }, - { { 32, DDS_PF_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 }, D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM }, - { { 32, DDS_PF_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 }, D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM }, - { { 32, DDS_PF_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0x000000 }, D3DX_PIXEL_FORMAT_B8G8R8_UNORM }, - { { 32, DDS_PF_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }, D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM }, - { { 32, DDS_PF_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_R16G16_UNORM }, - { { 32, DDS_PF_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 }, D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }, D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }, D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }, D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM }, - { { 32, DDS_PF_RGB | DDS_PF_ALPHA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 }, D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM }, - /* DDS_PF_INDEXED. */ - { { 32, DDS_PF_INDEXED, 0, 8 }, D3DX_PIXEL_FORMAT_P8_UINT }, - { { 32, DDS_PF_INDEXED | DDS_PF_ALPHA, 0, 16, 0, 0, 0, 0xff00, }, D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM }, - /* DDS_PF_LUMINANCE. */ - { { 32, DDS_PF_LUMINANCE, 0, 8, 0x00ff }, D3DX_PIXEL_FORMAT_L8_UNORM }, - { { 32, DDS_PF_LUMINANCE, 0, 16, 0xffff }, D3DX_PIXEL_FORMAT_L16_UNORM }, - { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x000f, 0, 0, 0x00f0 }, D3DX_PIXEL_FORMAT_L4A4_UNORM }, - { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, - /* Exceptional case, A8L8 can also have 8bpp. */ - { { 32, DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x00ff, 0, 0, 0xff00 }, D3DX_PIXEL_FORMAT_L8A8_UNORM }, - /* DDS_PF_ALPHA_ONLY. */ - { { 32, DDS_PF_ALPHA_ONLY, 0, 8, 0, 0, 0, 0xff }, D3DX_PIXEL_FORMAT_A8_UNORM }, - /* DDS_PF_BUMPDUDV. */ - { { 32, DDS_PF_BUMPDUDV, 0, 16, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM }, - { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }, D3DX_PIXEL_FORMAT_U16V16_SNORM }, - { { 32, DDS_PF_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }, D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM }, - { { 32, DDS_PF_BUMPDUDV | DDS_PF_ALPHA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }, D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM }, - /* DDS_PF_BUMPLUMINANCE. */ - { { 32, DDS_PF_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 }, D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM }, -}; - -static BOOL dds_pixel_format_compare(const struct dds_pixel_format *pf_a, const struct dds_pixel_format *pf_b, - BOOL check_rmask, BOOL check_gmask, BOOL check_bmask, BOOL check_amask) +void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) { - return pf_a->bpp == pf_b->bpp && !((check_rmask && pf_a->rmask != pf_b->rmask) - || (check_gmask && pf_a->gmask != pf_b->gmask) || (check_bmask && pf_a->bmask != pf_b->bmask) - || (check_amask && pf_a->amask != pf_b->amask)); + info->ImageFileFormat = (D3DXIMAGE_FILEFORMAT)image->image_file_format; + info->Width = image->size.width; + info->Height = image->size.height; + info->Depth = image->size.depth; + info->MipLevels = image->mip_levels; + switch (image->format) + { + case D3DX_PIXEL_FORMAT_P1_UINT: + case D3DX_PIXEL_FORMAT_P2_UINT: + case D3DX_PIXEL_FORMAT_P4_UINT: + info->Format = D3DFMT_P8; + break; + + case D3DX_PIXEL_FORMAT_R16G16B16_UNORM: + info->Format = D3DFMT_A16B16G16R16; + break; + + case D3DX_PIXEL_FORMAT_B8G8R8_UNORM: + if (info->ImageFileFormat == D3DXIFF_PNG || info->ImageFileFormat == D3DXIFF_JPG) + info->Format = D3DFMT_X8R8G8B8; + else + info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); + break; + + default: + info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); + break; + } + if (image->resource_type == D3DX_RESOURCE_TYPE_TEXTURE_3D) + info->ResourceType = D3DRTYPE_VOLUMETEXTURE; + else if (image->resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) + info->ResourceType = D3DRTYPE_CUBETEXTURE; + else + info->ResourceType = D3DRTYPE_TEXTURE; }
-static enum d3dx_pixel_format_id d3dx_pixel_format_id_from_dds_pixel_format(const struct dds_pixel_format *pixel_format) +/************************************************************ + * D3DXGetImageInfoFromFileInMemory + * + * Fills a D3DXIMAGE_INFO structure with info about an image + * + * PARAMS + * data [I] pointer to the image file data + * datasize [I] size of the passed data + * info [O] pointer to the destination structure + * + * RETURNS + * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or + * if info is NULL and data and datasize are not NULL + * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL + * D3DERR_INVALIDCALL, if data is NULL or + * if datasize is 0 + * + * NOTES + * datasize may be bigger than the actual file size + * + */ +HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) { - uint32_t i; + struct d3dx_image image; + HRESULT hr;
- TRACE("pixel_format: size %lu, flags %#lx, fourcc %#lx, bpp %lu.\n", pixel_format->size, - pixel_format->flags, pixel_format->fourcc, pixel_format->bpp); - TRACE("rmask %#lx, gmask %#lx, bmask %#lx, amask %#lx.\n", pixel_format->rmask, pixel_format->gmask, - pixel_format->bmask, pixel_format->amask); + TRACE("(%p, %d, %p)\n", data, datasize, info);
- for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) - { - const struct dds_pixel_format *dds_pf = &dds_pixel_formats[i].dds_pixel_format; + if (!data || !datasize) + return D3DERR_INVALIDCALL;
- if (pixel_format->flags != dds_pf->flags) - continue; + if (!info) + return D3D_OK;
- switch (pixel_format->flags & ~DDS_PF_ALPHA) - { - case DDS_PF_ALPHA_ONLY: - if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, TRUE)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_FOURCC: - if (pixel_format->fourcc == dds_pf->fourcc) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_INDEXED: - if (dds_pixel_format_compare(pixel_format, dds_pf, FALSE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_RGB: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, pixel_format->flags & DDS_PF_ALPHA)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_LUMINANCE: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, FALSE, FALSE, pixel_format->flags & DDS_PF_ALPHA)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_BUMPLUMINANCE: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, FALSE)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - case DDS_PF_BUMPDUDV: - if (dds_pixel_format_compare(pixel_format, dds_pf, TRUE, TRUE, TRUE, TRUE)) - return dds_pixel_formats[i].d3dx_pixel_format; - break; - - default: - assert(0); /* Should not happen. */ - break; - } + hr = d3dx_image_init(data, datasize, &image, 0, D3DX_IMAGE_INFO_ONLY); + if (FAILED(hr)) { + TRACE("Invalid or unsupported image file\n"); + return D3DXERR_INVALIDDATA; }
- WARN("Unknown pixel format (flags %#lx, fourcc %#lx, bpp %lu, r %#lx, g %#lx, b %#lx, a %#lx).\n", - pixel_format->flags, pixel_format->fourcc, pixel_format->bpp, - pixel_format->rmask, pixel_format->gmask, pixel_format->bmask, pixel_format->amask); - return D3DX_PIXEL_FORMAT_COUNT; + d3dximage_info_from_d3dx_image(info, &image); + return D3D_OK; }
-static HRESULT dds_pixel_format_from_d3dx_pixel_format_id(struct dds_pixel_format *pixel_format, - enum d3dx_pixel_format_id d3dx_pixel_format) +/************************************************************ + * D3DXGetImageInfoFromFile + * + * RETURNS + * Success: D3D_OK, if we successfully load a valid image file or + * if we successfully load a file which is no valid image and info is NULL + * Failure: D3DXERR_INVALIDDATA, if we fail to load file or + * if file is not a valid image file and info is not NULL + * D3DERR_INVALIDCALL, if file is NULL + * + */ +HRESULT WINAPI D3DXGetImageInfoFromFileA(const char *file, D3DXIMAGE_INFO *info) { - const struct dds_pixel_format *pf = NULL; - uint32_t i; + WCHAR *widename; + HRESULT hr; + int strlength;
- for (i = 0; i < ARRAY_SIZE(dds_pixel_formats); ++i) - { - if (dds_pixel_formats[i].d3dx_pixel_format == d3dx_pixel_format) - { - pf = &dds_pixel_formats[i].dds_pixel_format; - break; - } - } + TRACE("file %s, info %p.\n", debugstr_a(file), info);
- if (!pf) - { - WARN("Unhandled format %#x.\n", d3dx_pixel_format); - return E_NOTIMPL; - } + if( !file ) return D3DERR_INVALIDCALL;
- if (pixel_format) - *pixel_format = *pf; + strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); + widename = malloc(strlength * sizeof(*widename)); + MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength);
- return D3D_OK; -} + hr = D3DXGetImageInfoFromFileW(widename, info); + free(widename);
-static void d3dx_get_next_mip_level_size(struct volume *size) -{ - size->width = max(size->width / 2, 1); - size->height = max(size->height / 2, 1); - size->depth = max(size->depth / 2, 1); + return hr; }
-static const char *debug_volume(const struct volume *volume) +HRESULT WINAPI D3DXGetImageInfoFromFileW(const WCHAR *file, D3DXIMAGE_INFO *info) { - if (!volume) - return "(null)"; - return wine_dbg_sprintf("(%ux%ux%u)", volume->width, volume->height, volume->depth); + void *buffer; + HRESULT hr; + DWORD size; + + TRACE("file %s, info %p.\n", debugstr_w(file), info); + + if (!file) + return D3DERR_INVALIDCALL; + + if (FAILED(map_view_of_file(file, &buffer, &size))) + return D3DXERR_INVALIDDATA; + + hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info); + UnmapViewOfFile(buffer); + + return hr; }
-static HRESULT d3dx_calculate_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, - uint32_t *pitch, uint32_t *size) +/************************************************************ + * D3DXGetImageInfoFromResource + * + * RETURNS + * Success: D3D_OK, if resource is a valid image file + * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or + * if we fail to load resource + * + */ +HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, const char *resource, D3DXIMAGE_INFO *info) { - const struct pixel_format_desc *format_desc = get_d3dx_pixel_format_info(format); + HRSRC resinfo; + void *buffer; + DWORD size;
- if (is_unknown_format(format_desc)) - return E_NOTIMPL; + TRACE("module %p, resource %s, info %p.\n", module, debugstr_a(resource), info);
- if (format_desc->block_width != 1 || format_desc->block_height != 1) - { - *pitch = format_desc->block_byte_count - * max(1, (width + format_desc->block_width - 1) / format_desc->block_width); - *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; - } + if (!(resinfo = FindResourceA(module, resource, (const char *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceA(module, resource, (const char *)RT_BITMAP))) + return D3DXERR_INVALIDDATA;
- return D3D_OK; + if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) + return D3DXERR_INVALIDDATA; + + return D3DXGetImageInfoFromFileInMemory(buffer, size, info); }
-uint32_t d3dx_calculate_layer_pixels_size(enum d3dx_pixel_format_id format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t mip_levels) +HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, D3DXIMAGE_INFO *info) { - uint32_t layer_size, row_pitch, slice_pitch, i; - struct volume dims = { width, height, depth }; + HRSRC resinfo; + void *buffer; + DWORD size;
- layer_size = 0; - for (i = 0; i < mip_levels; ++i) - { - if (FAILED(d3dx_calculate_pixels_size(format, dims.width, dims.height, &row_pitch, &slice_pitch))) - return 0; - layer_size += slice_pitch * dims.depth; - d3dx_get_next_mip_level_size(&dims); - } + TRACE("module %p, resource %s, info %p.\n", module, debugstr_w(resource), info); + + if (!(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP))) + return D3DXERR_INVALIDDATA; + + if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) + return D3DXERR_INVALIDDATA;
- return layer_size; + return D3DXGetImageInfoFromFileInMemory(buffer, size, info); }
-HRESULT d3dx_init_dds_header(struct dds_header *header, enum d3dx_resource_type resource_type, - enum d3dx_pixel_format_id format, const struct volume *size, uint32_t mip_levels) +static HRESULT d3dx_load_surface_from_memory(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory, + enum d3dx_pixel_format_id src_format, uint32_t src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, + DWORD filter, D3DCOLOR color_key) { + const struct pixel_format_desc *src_desc, *dst_desc; + struct d3dx_pixels src_pixels, dst_pixels; + RECT dst_rect_tmp, dst_rect_aligned; + IDirect3DSurface9 *surface; + D3DLOCKED_RECT lock_rect; + D3DSURFACE_DESC desc; HRESULT hr;
- 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) - FIELD_OFFSET(struct dds_header, size); - hr = dds_pixel_format_from_d3dx_pixel_format_id(&header->pixel_format, format); - if (FAILED(hr)) - return hr; - - header->flags = DDS_CAPS | DDS_HEIGHT | DDS_WIDTH | DDS_PIXELFORMAT; - header->height = size->height; - header->width = size->width; - header->caps = DDS_CAPS_TEXTURE; - if (size->depth > 1) + IDirect3DSurface9_GetDesc(dst_surface, &desc); + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) { - header->flags |= DDS_DEPTH; - header->depth = size->depth; - header->caps2 |= DDS_CAPS2_VOLUME; + TRACE("Multisampled destination surface, doing nothing.\n"); + return D3D_OK; }
- if (mip_levels > 1) + dst_desc = get_format_info(desc.Format); + if (!dst_rect) { - header->flags |= DDS_MIPMAPCOUNT; - header->caps |= (DDS_CAPS_MIPMAP | DDS_CAPS_COMPLEX); - header->miplevels = mip_levels; + SetRect(&dst_rect_tmp, 0, 0, desc.Width, desc.Height); + dst_rect = &dst_rect_tmp; } - - if (resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) + else { - header->caps |= DDS_CAPS_COMPLEX; - header->caps2 |= (DDS_CAPS2_CUBEMAP | DDS_CAPS2_CUBEMAP_ALL_FACES); + if (dst_rect->left > dst_rect->right || dst_rect->right > desc.Width + || dst_rect->top > dst_rect->bottom || dst_rect->bottom > desc.Height + || dst_rect->left < 0 || dst_rect->top < 0) + { + WARN("Invalid dst_rect specified.\n"); + return D3DERR_INVALIDCALL; + } + if (dst_rect->left == dst_rect->right || dst_rect->top == dst_rect->bottom) + { + WARN("Empty dst_rect specified.\n"); + return D3D_OK; + } }
- if (header->pixel_format.flags & DDS_PF_ALPHA || header->pixel_format.flags & DDS_PF_ALPHA_ONLY) - header->caps |= DDSCAPS_ALPHA; - if (header->pixel_format.flags & DDS_PF_INDEXED) - header->caps |= DDSCAPS_PALETTE; + src_desc = get_d3dx_pixel_format_info(src_format); + hr = d3dx_pixels_init(src_memory, src_pitch, 0, src_palette, src_desc->format, + src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); + if (FAILED(hr)) + return hr;
- return D3D_OK; -} + get_aligned_rect(dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, desc.Width, desc.Height, + dst_desc, &dst_rect_aligned); + if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lock_rect, &surface, TRUE))) + return hr;
-static const GUID *wic_container_guid_from_d3dx_file_format(enum d3dx_image_file_format iff) -{ - switch (iff) + set_d3dx_pixels(&dst_pixels, lock_rect.pBits, lock_rect.Pitch, 0, dst_palette, + (dst_rect_aligned.right - dst_rect_aligned.left), (dst_rect_aligned.bottom - dst_rect_aligned.top), 1, + dst_rect); + OffsetRect(&dst_pixels.unaligned_rect, -dst_rect_aligned.left, -dst_rect_aligned.top); + + if (FAILED(hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_desc, &src_pixels, src_desc, filter, color_key))) { - case D3DX_IMAGE_FILE_FORMAT_DIB: - case D3DX_IMAGE_FILE_FORMAT_BMP: return &GUID_ContainerFormatBmp; - case D3DX_IMAGE_FILE_FORMAT_JPG: return &GUID_ContainerFormatJpeg; - case D3DX_IMAGE_FILE_FORMAT_PNG: return &GUID_ContainerFormatPng; - default: - assert(0 && "Unexpected file format."); - return NULL; + unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); + return hr; } -}
-static HRESULT d3dx_pixels_save_wic(struct d3dx_pixels *pixels, const struct pixel_format_desc *fmt_desc, - enum d3dx_image_file_format image_file_format, IStream **wic_file, uint32_t *wic_file_size) -{ - const GUID *container_format = wic_container_guid_from_d3dx_file_format(image_file_format); - const GUID *pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(fmt_desc->format); - IWICBitmapFrameEncode *wic_frame = NULL; - IPropertyBag2 *encoder_options = NULL; - IWICBitmapEncoder *wic_encoder = NULL; - WICPixelFormatGUID wic_pixel_format; - const LARGE_INTEGER seek = { 0 }; - IWICImagingFactory *wic_factory; - IWICPalette *wic_palette = NULL; - IStream *stream = NULL; - STATSTG stream_stats; - HRESULT hr; - - assert(container_format && pixel_format_guid); - hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); - if (FAILED(hr)) - return D3DERR_INVALIDCALL; - - hr = IWICImagingFactory_CreateEncoder(wic_factory, container_format, NULL, &wic_encoder); - if (FAILED(hr)) - { - hr = D3DERR_INVALIDCALL; - goto exit; - } - - hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapEncoder_Initialize(wic_encoder, stream, WICBitmapEncoderNoCache); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapEncoder_CreateNewFrame(wic_encoder, &wic_frame, &encoder_options); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameEncode_Initialize(wic_frame, encoder_options); - if (FAILED(hr)) - goto exit; - - if (image_file_format == D3DX_IMAGE_FILE_FORMAT_JPG) - FIXME("JPEG saving quality adjustment currently unimplemented, expect lower quality JPEG.\n"); - - hr = IWICBitmapFrameEncode_SetSize(wic_frame, pixels->size.width, pixels->size.height); - if (FAILED(hr)) - goto exit; - - if (pixels->palette) - { - WICColor tmp_palette[256]; - unsigned int i; - - hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); - if (FAILED(hr)) - goto exit; - - for (i = 0; i < ARRAY_SIZE(tmp_palette); ++i) - { - const PALETTEENTRY *pe = &pixels->palette[i]; - - tmp_palette[i] = (pe->peFlags << 24) | (pe->peRed << 16) | (pe->peGreen << 8) | (pe->peBlue); - } - - hr = IWICPalette_InitializeCustom(wic_palette, tmp_palette, ARRAY_SIZE(tmp_palette)); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameEncode_SetPalette(wic_frame, wic_palette); - if (FAILED(hr)) - goto exit; - } - - /* - * Encode 32bpp BGRA format surfaces as 32bpp BGRX for BMP. - * This matches the behavior of native. - */ - if (IsEqualGUID(&GUID_ContainerFormatBmp, container_format) && (fmt_desc->format == D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM)) - pixel_format_guid = wic_guid_from_d3dx_pixel_format_id(D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM); - - wic_pixel_format = *pixel_format_guid; - hr = IWICBitmapFrameEncode_SetPixelFormat(wic_frame, &wic_pixel_format); - if (FAILED(hr)) - goto exit; - - if (!IsEqualGUID(pixel_format_guid, &wic_pixel_format)) - { - ERR("SetPixelFormat returned a different pixel format.\n"); - hr = E_FAIL; - goto exit; - } - - hr = IWICBitmapFrameEncode_WritePixels(wic_frame, pixels->size.height, pixels->row_pitch, pixels->slice_pitch, - (BYTE *)pixels->data); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameEncode_Commit(wic_frame); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapEncoder_Commit(wic_encoder); - if (FAILED(hr)) - goto exit; - - hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); - if (FAILED(hr)) - goto exit; - - hr = IStream_Stat(stream, &stream_stats, STATFLAG_NONAME); - if (FAILED(hr)) - goto exit; - - if (!stream_stats.cbSize.u.HighPart && !!stream_stats.cbSize.u.LowPart) - { - *wic_file = stream; - *wic_file_size = stream_stats.cbSize.u.LowPart; - } - else - { - hr = D3DXERR_INVALIDDATA; - } - -exit: - if (wic_factory) - IWICImagingFactory_Release(wic_factory); - if (stream && (*wic_file != stream)) - IStream_Release(stream); - if (wic_frame) - IWICBitmapFrameEncode_Release(wic_frame); - if (wic_palette) - IWICPalette_Release(wic_palette); - if (encoder_options) - IPropertyBag2_Release(encoder_options); - if (wic_encoder) - IWICBitmapEncoder_Release(wic_encoder); - - return hr; -} - -static const enum d3dx_pixel_format_id tga_save_pixel_formats[] = -{ - D3DX_PIXEL_FORMAT_B8G8R8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM -}; - -static const enum d3dx_pixel_format_id png_save_pixel_formats[] = -{ - D3DX_PIXEL_FORMAT_B8G8R8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, - D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM -}; - -static const enum d3dx_pixel_format_id jpg_save_pixel_formats[] = -{ - D3DX_PIXEL_FORMAT_B8G8R8_UNORM, -}; - -static const enum d3dx_pixel_format_id bmp_save_pixel_formats[] = -{ - D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, - D3DX_PIXEL_FORMAT_B5G6R5_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, - D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, - D3DX_PIXEL_FORMAT_P8_UINT, -}; - -static const enum d3dx_pixel_format_id unimplemented_bmp_save_pixel_formats[] = -{ - D3DX_PIXEL_FORMAT_A8_UNORM, - D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, - D3DX_PIXEL_FORMAT_L8A8_UNORM, - D3DX_PIXEL_FORMAT_L16_UNORM, - D3DX_PIXEL_FORMAT_B2G3R3_UNORM, - D3DX_PIXEL_FORMAT_R16_FLOAT, - D3DX_PIXEL_FORMAT_R16G16_FLOAT, - D3DX_PIXEL_FORMAT_R16G16_UNORM, - D3DX_PIXEL_FORMAT_R32_FLOAT, - D3DX_PIXEL_FORMAT_R32G32_FLOAT, - D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, - D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, - D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, - D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, - D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, - D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, - D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, - D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, -}; - -static enum d3dx_pixel_format_id d3dx_get_closest_d3dx_pixel_format_id(const enum d3dx_pixel_format_id *format_ids, - uint32_t format_ids_size, enum d3dx_pixel_format_id format_id) -{ - const struct pixel_format_desc *fmt, *curfmt, *bestfmt = NULL; - int bestscore = INT_MIN, rgb_channels, a_channel, i, j; - BOOL alpha_only, rgb_only; - - for (i = 0; i < format_ids_size; ++i) - { - if (format_ids[i] == format_id) - return format_id; - } - - TRACE("Requested format is not directly supported, looking for the best alternative.\n"); - switch (format_id) - { - case D3DX_PIXEL_FORMAT_P8_UINT: - case D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM: - case D3DX_PIXEL_FORMAT_DXT1_UNORM: - case D3DX_PIXEL_FORMAT_DXT2_UNORM: - case D3DX_PIXEL_FORMAT_DXT3_UNORM: - case D3DX_PIXEL_FORMAT_DXT4_UNORM: - case D3DX_PIXEL_FORMAT_DXT5_UNORM: - fmt = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM); - break; - - default: - fmt = get_d3dx_pixel_format_info(format_id); - break; - } - - alpha_only = rgb_only = FALSE; - if (fmt->a_type != CTYPE_EMPTY && fmt->rgb_type == CTYPE_EMPTY) - alpha_only = TRUE; - else if (fmt->a_type == CTYPE_EMPTY && fmt->rgb_type != CTYPE_EMPTY) - rgb_only = TRUE; - - if (fmt->rgb_type == CTYPE_LUMA) - rgb_channels = 3; - else - rgb_channels = !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3]; - a_channel = !!fmt->bits[0]; - for (i = 0; i < format_ids_size; ++i) - { - int cur_rgb_channels, cur_a_channel, score; - - curfmt = get_d3dx_pixel_format_info(format_ids[i]); - if (!is_conversion_to_supported(curfmt)) - continue; - if (alpha_only && curfmt->a_type == CTYPE_EMPTY) - continue; - if (rgb_only && curfmt->rgb_type == CTYPE_EMPTY) - continue; - if (fmt->rgb_type == CTYPE_SNORM && curfmt->rgb_type != CTYPE_SNORM) - continue; - - cur_rgb_channels = !!curfmt->bits[1] + !!curfmt->bits[2] + !!curfmt->bits[3]; - cur_a_channel = !!curfmt->bits[0]; - /* Calculate a score for this format. */ - score = 512 * (format_types_match(curfmt, fmt)); - score -= 32 * abs(cur_a_channel - a_channel); - score -= 32 * abs(cur_rgb_channels - rgb_channels); - for (j = 0; j < 4; ++j) - { - int diff = curfmt->bits[j] - fmt->bits[j]; - - score -= (diff < 0 ? -diff * 8 : diff) * (j == 0 ? 1 : 2); - } - - if (score > bestscore) - { - bestscore = score; - bestfmt = curfmt; - } - } - - return (bestfmt) ? bestfmt->format : D3DX_PIXEL_FORMAT_COUNT; -} - -HRESULT d3dx_save_pixels_to_memory(struct d3dx_pixels *src_pixels, const struct pixel_format_desc *src_fmt_desc, - enum d3dx_image_file_format file_format, ID3DXBuffer **dst_buffer) -{ - enum d3dx_pixel_format_id dst_format = src_fmt_desc->format; - const struct pixel_format_desc *dst_fmt_desc; - uint32_t dst_row_pitch, dst_slice_pitch; - struct d3dx_pixels dst_pixels; - uint8_t *pixels, *tmp_buf; - ID3DXBuffer *buffer; - HRESULT hr; - - *dst_buffer = buffer = NULL; - pixels = tmp_buf = NULL; - switch (file_format) - { - case D3DX_IMAGE_FILE_FORMAT_DDS: - hr = dds_pixel_format_from_d3dx_pixel_format_id(NULL, dst_format); - if (FAILED(hr)) - return hr; - break; - - case D3DX_IMAGE_FILE_FORMAT_TGA: - dst_format = d3dx_get_closest_d3dx_pixel_format_id(tga_save_pixel_formats, ARRAY_SIZE(tga_save_pixel_formats), - dst_format); - break; - - case D3DX_IMAGE_FILE_FORMAT_PNG: - dst_format = d3dx_get_closest_d3dx_pixel_format_id(png_save_pixel_formats, ARRAY_SIZE(png_save_pixel_formats), - dst_format); - break; - - case D3DX_IMAGE_FILE_FORMAT_JPG: - dst_format = d3dx_get_closest_d3dx_pixel_format_id(jpg_save_pixel_formats, ARRAY_SIZE(jpg_save_pixel_formats), - dst_format); - break; - - case D3DX_IMAGE_FILE_FORMAT_BMP: - case D3DX_IMAGE_FILE_FORMAT_DIB: - { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(unimplemented_bmp_save_pixel_formats); ++i) - { - if (unimplemented_bmp_save_pixel_formats[i] == dst_format) - { - FIXME("Saving pixel format %d to BMP files is currently unsupported.\n", dst_format); - return E_NOTIMPL; - } - } - dst_format = d3dx_get_closest_d3dx_pixel_format_id(bmp_save_pixel_formats, ARRAY_SIZE(bmp_save_pixel_formats), - dst_format); - break; - } - - default: - assert(0 && "Unexpected file format."); - return E_FAIL; - } - - if (dst_format == D3DX_PIXEL_FORMAT_COUNT) - { - WARN("Failed to find adequate replacement format for saving.\n"); - return D3DERR_INVALIDCALL; - } - - if (dst_format != src_fmt_desc->format && !is_conversion_from_supported(src_fmt_desc)) - { - FIXME("Cannot convert d3dx pixel format %d, can't save.\n", src_fmt_desc->format); - return E_NOTIMPL; - } - - dst_fmt_desc = get_d3dx_pixel_format_info(dst_format); - src_pixels->size.depth = (file_format == D3DX_IMAGE_FILE_FORMAT_DDS) ? src_pixels->size.depth : 1; - hr = d3dx_calculate_pixels_size(dst_format, src_pixels->size.width, src_pixels->size.height, &dst_row_pitch, - &dst_slice_pitch); - if (FAILED(hr)) - return hr; - - switch (file_format) - { - case D3DX_IMAGE_FILE_FORMAT_DDS: - { - struct dds_header *header; - uint32_t header_size; - - header_size = is_index_format(dst_fmt_desc) ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); - hr = D3DXCreateBuffer((dst_slice_pitch * src_pixels->size.depth) + header_size, &buffer); - if (FAILED(hr)) - return hr; - - header = ID3DXBuffer_GetBufferPointer(buffer); - pixels = (uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + header_size; - hr = d3dx_init_dds_header(header, D3DX_RESOURCE_TYPE_TEXTURE_2D, dst_format, &src_pixels->size, 1); - if (FAILED(hr)) - goto exit; - if (is_index_format(dst_fmt_desc)) - memcpy((uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(*header), src_pixels->palette, - DDS_PALETTE_SIZE); - break; - } - - case D3DX_IMAGE_FILE_FORMAT_TGA: - { - struct tga_header *header; - - hr = D3DXCreateBuffer(dst_slice_pitch + sizeof(*header), &buffer); - if (FAILED(hr)) - return hr; - - header = ID3DXBuffer_GetBufferPointer(buffer); - pixels = (uint8_t *)ID3DXBuffer_GetBufferPointer(buffer) + sizeof(*header); - - memset(header, 0, sizeof(*header)); - header->image_type = TGA_IMAGETYPE_TRUECOLOR; - header->width = src_pixels->size.width; - header->height = src_pixels->size.height; - header->image_descriptor = TGA_IMAGE_TOPTOBOTTOM; - header->depth = dst_fmt_desc->bytes_per_pixel * 8; - if (dst_fmt_desc->format == D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) - header->image_descriptor |= 0x08; - break; - } - - case D3DX_IMAGE_FILE_FORMAT_PNG: - case D3DX_IMAGE_FILE_FORMAT_JPG: - case D3DX_IMAGE_FILE_FORMAT_BMP: - case D3DX_IMAGE_FILE_FORMAT_DIB: - if (src_fmt_desc == dst_fmt_desc) - dst_pixels = *src_pixels; - else - pixels = tmp_buf = malloc(dst_slice_pitch); - break; - - default: - break; - } - - if (src_pixels->size.width != 0 && src_pixels->size.height != 0) - { - if (pixels) - { - const PALETTEENTRY *dst_palette = is_index_format(dst_fmt_desc) ? src_pixels->palette : NULL; - const RECT dst_rect = { 0, 0, src_pixels->size.width, src_pixels->size.height }; - - set_d3dx_pixels(&dst_pixels, pixels, dst_row_pitch, dst_slice_pitch, dst_palette, - src_pixels->size.width, src_pixels->size.height, src_pixels->size.depth, &dst_rect); - - hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_fmt_desc, src_pixels, src_fmt_desc, D3DX_FILTER_NONE, 0); - if (FAILED(hr)) - goto exit; - } - - /* WIC path, encode the image. */ - if (!buffer) - { - IStream *wic_file = NULL; - uint32_t buf_size = 0; - - hr = d3dx_pixels_save_wic(&dst_pixels, dst_fmt_desc, file_format, &wic_file, &buf_size); - if (FAILED(hr)) - goto exit; - hr = D3DXCreateBuffer(buf_size, &buffer); - if (FAILED(hr)) - { - IStream_Release(wic_file); - goto exit; - } - - hr = IStream_Read(wic_file, ID3DXBuffer_GetBufferPointer(buffer), buf_size, NULL); - IStream_Release(wic_file); - if (FAILED(hr)) - goto exit; - } - } - /* Return an empty buffer for size 0 images via WIC. */ - else if (!buffer) - { - FIXME("Returning empty buffer for size 0 image.\n"); - hr = D3DXCreateBuffer(64, &buffer); - if (FAILED(hr)) - goto exit; - } - - *dst_buffer = buffer; -exit: - free(tmp_buf); - if (*dst_buffer != buffer) - ID3DXBuffer_Release(buffer); - return hr; -} - -static const uint8_t bmp_file_signature[] = { 'B', 'M' }; -static const uint8_t jpg_file_signature[] = { 0xff, 0xd8 }; -static const uint8_t png_file_signature[] = { 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a }; -static const uint8_t dds_file_signature[] = { 'D', 'D', 'S', ' ' }; -static const uint8_t ppm_plain_file_signature[] = { 'P', '3' }; -static const uint8_t ppm_raw_file_signature[] = { 'P', '6' }; -static const uint8_t hdr_file_signature[] = { '#', '?', 'R', 'A', 'D', 'I', 'A', 'N', 'C', 'E', '\n' }; -static const uint8_t pfm_color_file_signature[] = { 'P', 'F' }; -static const uint8_t pfm_gray_file_signature[] = { 'P', 'f' }; - -/* - * If none of these match, the file is either DIB, TGA, or something we don't - * support. - */ -struct d3dx_file_format_signature -{ - const uint8_t *file_signature; - uint32_t file_signature_len; - enum d3dx_image_file_format image_file_format; -}; - -static const struct d3dx_file_format_signature file_format_signatures[] = -{ - { bmp_file_signature, sizeof(bmp_file_signature), D3DX_IMAGE_FILE_FORMAT_BMP }, - { jpg_file_signature, sizeof(jpg_file_signature), D3DX_IMAGE_FILE_FORMAT_JPG }, - { png_file_signature, sizeof(png_file_signature), D3DX_IMAGE_FILE_FORMAT_PNG }, - { dds_file_signature, sizeof(dds_file_signature), D3DX_IMAGE_FILE_FORMAT_DDS }, - { ppm_plain_file_signature, sizeof(ppm_plain_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, - { ppm_raw_file_signature, sizeof(ppm_raw_file_signature), D3DX_IMAGE_FILE_FORMAT_PPM }, - { hdr_file_signature, sizeof(hdr_file_signature), D3DX_IMAGE_FILE_FORMAT_HDR }, - { pfm_color_file_signature, sizeof(pfm_color_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, - { pfm_gray_file_signature, sizeof(pfm_gray_file_signature), D3DX_IMAGE_FILE_FORMAT_PFM }, -}; - -static BOOL d3dx_get_image_file_format_from_file_signature(const void *src_data, uint32_t src_data_size, - enum d3dx_image_file_format *out_iff) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(file_format_signatures); ++i) - { - const struct d3dx_file_format_signature *signature = &file_format_signatures[i]; - - if ((src_data_size >= signature->file_signature_len) - && !memcmp(src_data, signature->file_signature, signature->file_signature_len)) - { - *out_iff = signature->image_file_format; - return TRUE; - } - } - - return FALSE; -} - -static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image, uint32_t starting_mip_level) -{ - uint32_t expected_src_data_size, header_size; - const struct dds_header *header = src_data; - BOOL is_indexed_fmt; - HRESULT hr; - - if (src_data_size < sizeof(*header) || header->pixel_format.size != sizeof(header->pixel_format)) - return D3DXERR_INVALIDDATA; - - TRACE("File type is DDS.\n"); - is_indexed_fmt = !!(header->pixel_format.flags & DDS_PF_INDEXED); - header_size = is_indexed_fmt ? sizeof(*header) + DDS_PALETTE_SIZE : sizeof(*header); - - set_volume_struct(&image->size, header->width, header->height, 1); - image->mip_levels = header->miplevels ? header->miplevels : 1; - image->format = d3dx_pixel_format_id_from_dds_pixel_format(&header->pixel_format); - image->layer_count = 1; - - if (image->format == D3DX_PIXEL_FORMAT_COUNT) - return D3DXERR_INVALIDDATA; - - TRACE("Pixel format is %#x.\n", image->format); - if (header->flags & DDS_DEPTH) - { - image->size.depth = max(header->depth, 1); - image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_3D; - } - else if (header->caps2 & DDS_CAPS2_CUBEMAP) - { - if ((header->caps2 & DDS_CAPS2_CUBEMAP_ALL_FACES) != DDS_CAPS2_CUBEMAP_ALL_FACES) - { - WARN("Tried to load a partial cubemap DDS file.\n"); - return D3DXERR_INVALIDDATA; - } - - image->layer_count = 6; - image->resource_type = D3DX_RESOURCE_TYPE_CUBE_TEXTURE; - } - else - { - image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; - } - - image->layer_pitch = d3dx_calculate_layer_pixels_size(image->format, image->size.width, image->size.height, - image->size.depth, image->mip_levels); - if (!image->layer_pitch) - return D3DXERR_INVALIDDATA; - expected_src_data_size = (image->layer_pitch * image->layer_count) + header_size; - 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->palette = (is_indexed_fmt) ? (PALETTEENTRY *)(((uint8_t *)src_data) + sizeof(*header)) : NULL; - image->pixels = ((BYTE *)src_data) + header_size; - image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DDS; - if (starting_mip_level && (image->mip_levels > 1)) - { - uint32_t i, row_pitch, slice_pitch, initial_mip_levels; - const struct volume initial_size = image->size; - - initial_mip_levels = image->mip_levels; - for (i = 0; i < starting_mip_level; i++) - { - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - image->pixels += slice_pitch * image->size.depth; - d3dx_get_next_mip_level_size(&image->size); - if (--image->mip_levels == 1) - break; - } - - TRACE("Requested starting mip level %u, actual starting mip level is %u (of %u total in image).\n", - starting_mip_level, (initial_mip_levels - image->mip_levels), initial_mip_levels); - TRACE("Original dimensions %s, new dimensions %s.\n", debug_volume(&initial_size), debug_volume(&image->size)); - } - - return D3D_OK; -} - -static BOOL convert_dib_to_bmp(const void **data, unsigned int *size) -{ - ULONG header_size; - ULONG count = 0; - ULONG offset; - BITMAPFILEHEADER *header; - BYTE *new_data; - UINT new_size; - - if ((*size < 4) || (*size < (header_size = *(ULONG*)*data))) - return FALSE; - - if ((header_size == sizeof(BITMAPINFOHEADER)) || - (header_size == sizeof(BITMAPV4HEADER)) || - (header_size == sizeof(BITMAPV5HEADER)) || - (header_size == 64 /* sizeof(BITMAPCOREHEADER2) */)) - { - /* All structures begin with the same memory layout as BITMAPINFOHEADER */ - BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER*)*data; - count = info_header->biClrUsed; - - if (!count && info_header->biBitCount <= 8) - count = 1 << info_header->biBitCount; - - offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBQUAD) * count; - - /* For BITMAPINFOHEADER with BI_BITFIELDS compression, there are 3 additional color masks after header */ - if ((info_header->biSize == sizeof(BITMAPINFOHEADER)) && (info_header->biCompression == BI_BITFIELDS)) - offset += 3 * sizeof(DWORD); - } - else if (header_size == sizeof(BITMAPCOREHEADER)) - { - BITMAPCOREHEADER *core_header = (BITMAPCOREHEADER*)*data; - - if (core_header->bcBitCount <= 8) - count = 1 << core_header->bcBitCount; - - offset = sizeof(BITMAPFILEHEADER) + header_size + sizeof(RGBTRIPLE) * count; - } - else - { - return FALSE; - } - - TRACE("Converting DIB file to BMP\n"); - - new_size = *size + sizeof(BITMAPFILEHEADER); - new_data = malloc(new_size); - CopyMemory(new_data + sizeof(BITMAPFILEHEADER), *data, *size); - - /* Add BMP header */ - header = (BITMAPFILEHEADER*)new_data; - header->bfType = 0x4d42; /* BM */ - header->bfSize = new_size; - header->bfReserved1 = 0; - header->bfReserved2 = 0; - header->bfOffBits = offset; - - /* Update input data */ - *data = new_data; - *size = new_size; - - return TRUE; -} - -/* 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, struct d3dx_image *image) -{ - unsigned int size, i; - BYTE *buffer; - HRESULT hr; - - if (image->format != D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM || image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) - return FALSE; - - size = image->size.width * image->size.height * 4; - if (!(buffer = malloc(size))) - return FALSE; - - if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->size.width * 4, size, buffer))) - { - ERR("Failed to copy pixels, hr %#lx.\n", hr); - free(buffer); - return FALSE; - } - - for (i = 0; i < image->size.width * image->size.height; ++i) - { - if (buffer[i * 4 + 3]) - { - free(buffer); - return TRUE; - } - } - - free(buffer); - return FALSE; -} - -const char *debug_d3dx_image_file_format(enum d3dx_image_file_format format) -{ - switch (format) - { -#define FMT_TO_STR(format) case format: return #format - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_BMP); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_JPG); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_TGA); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PNG); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DDS); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PPM); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_DIB); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_HDR); - FMT_TO_STR(D3DX_IMAGE_FILE_FORMAT_PFM); -#undef FMT_TO_STR - default: - return "unrecognized"; - } -} - -static HRESULT d3dx_image_wic_frame_decode(struct d3dx_image *image, - IWICImagingFactory *wic_factory, IWICBitmapFrameDecode *bitmap_frame) -{ - const struct pixel_format_desc *fmt_desc; - uint32_t row_pitch, slice_pitch; - IWICPalette *wic_palette = NULL; - PALETTEENTRY *palette = NULL; - WICColor *colors = NULL; - BYTE *buffer = NULL; - HRESULT hr; - - fmt_desc = get_d3dx_pixel_format_info(image->format); - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - /* Allocate a buffer for our image. */ - if (!(buffer = malloc(slice_pitch))) - return E_OUTOFMEMORY; - - hr = IWICBitmapFrameDecode_CopyPixels(bitmap_frame, NULL, row_pitch, slice_pitch, buffer); - if (FAILED(hr)) - { - free(buffer); - return hr; - } - - if (is_index_format(fmt_desc)) - { - uint32_t nb_colors, i; - - hr = IWICImagingFactory_CreatePalette(wic_factory, &wic_palette); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameDecode_CopyPalette(bitmap_frame, wic_palette); - if (FAILED(hr)) - goto exit; - - hr = IWICPalette_GetColorCount(wic_palette, &nb_colors); - if (FAILED(hr)) - goto exit; - - colors = malloc(nb_colors * sizeof(colors[0])); - palette = malloc(256 * sizeof(palette[0])); - if (!colors || !palette) - { - hr = E_OUTOFMEMORY; - goto exit; - } - - hr = IWICPalette_GetColors(wic_palette, nb_colors, colors, &nb_colors); - if (FAILED(hr)) - goto exit; - - /* Convert colors from WICColor (ARGB) to PALETTEENTRY (ABGR) */ - for (i = 0; i < nb_colors; i++) - { - palette[i].peRed = (colors[i] >> 16) & 0xff; - palette[i].peGreen = (colors[i] >> 8) & 0xff; - palette[i].peBlue = colors[i] & 0xff; - palette[i].peFlags = (colors[i] >> 24) & 0xff; /* peFlags is the alpha component in DX8 and higher */ - } - if (nb_colors < 256) - memset(&palette[nb_colors], 0xff, sizeof(*palette) * (256 - nb_colors)); - } - - image->image_buf = image->pixels = buffer; - image->image_palette = image->palette = palette; - -exit: - free(colors); - if (image->image_buf != buffer) - free(buffer); - if (image->image_palette != palette) - free(palette); - if (wic_palette) - IWICPalette_Release(wic_palette); - - return hr; -} - -static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src_data_size, - struct d3dx_image *image, enum d3dx_image_file_format d3dx_file_format, uint32_t flags) -{ - const GUID *container_format_guid = wic_container_guid_from_d3dx_file_format(d3dx_file_format); - IWICBitmapFrameDecode *bitmap_frame = NULL; - IWICBitmapDecoder *bitmap_decoder = NULL; - IWICImagingFactory *wic_factory; - WICPixelFormatGUID pixel_format; - IWICStream *wic_stream = NULL; - uint32_t frame_count = 0; - HRESULT hr; - - hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &wic_factory); - if (FAILED(hr)) - return hr; - - hr = IWICImagingFactory_CreateDecoder(wic_factory, container_format_guid, NULL, &bitmap_decoder); - if (FAILED(hr)) - goto exit; - - hr = IWICImagingFactory_CreateStream(wic_factory, &wic_stream); - if (FAILED(hr)) - goto exit; - - hr = IWICStream_InitializeFromMemory(wic_stream, (BYTE *)src_data, src_data_size); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapDecoder_Initialize(bitmap_decoder, (IStream *)wic_stream, 0); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapDecoder_GetFrameCount(bitmap_decoder, &frame_count); - if (FAILED(hr) || (SUCCEEDED(hr) && !frame_count)) - { - hr = D3DXERR_INVALIDDATA; - goto exit; - } - - image->image_file_format = d3dx_file_format; - hr = IWICBitmapDecoder_GetFrame(bitmap_decoder, 0, &bitmap_frame); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->size.width, &image->size.height); - if (FAILED(hr)) - goto exit; - - hr = IWICBitmapFrameDecode_GetPixelFormat(bitmap_frame, &pixel_format); - if (FAILED(hr)) - goto exit; - - image->format = d3dx_pixel_format_id_from_wic_pixel_format(&pixel_format); - switch (image->format) - { - case D3DX_PIXEL_FORMAT_P2_UINT: - if (image->image_file_format != D3DX_IMAGE_FILE_FORMAT_BMP) - break; - /* Fall through. */ - - case D3DX_PIXEL_FORMAT_COUNT: - WARN("Unsupported pixel format %s.\n", debugstr_guid(&pixel_format)); - hr = D3DXERR_INVALIDDATA; - goto exit; - - default: - break; - } - - if (image_is_argb(bitmap_frame, image)) - image->format = D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; - - if (!(flags & D3DX_IMAGE_INFO_ONLY)) - { - hr = d3dx_image_wic_frame_decode(image, wic_factory, bitmap_frame); - if (FAILED(hr)) - goto exit; - } - - image->size.depth = 1; - image->mip_levels = 1; - image->layer_count = 1; - image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; - -exit: - if (bitmap_frame) - IWICBitmapFrameDecode_Release(bitmap_frame); - if (bitmap_decoder) - IWICBitmapDecoder_Release(bitmap_decoder); - if (wic_stream) - IWICStream_Release(wic_stream); - IWICImagingFactory_Release(wic_factory); - - return hr; -} - -static enum d3dx_pixel_format_id d3dx_get_tga_format_for_bpp(uint8_t bpp) -{ - switch (bpp) - { - case 15: return D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM; - case 16: return D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM; - case 24: return D3DX_PIXEL_FORMAT_B8G8R8_UNORM; - case 32: return D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM; - default: - WARN("Unhandled bpp %u for targa.\n", bpp); - return D3DX_PIXEL_FORMAT_COUNT; - } -} - -static HRESULT d3dx_image_tga_rle_decode_row(const uint8_t **src, uint32_t src_bytes_left, uint32_t row_width, - uint32_t bytes_per_pixel, uint8_t *dst_row) -{ - const uint8_t *src_ptr = *src; - uint32_t pixel_count = 0; - - while (pixel_count != row_width) - { - uint32_t rle_count = (src_ptr[0] & 0x7f) + 1; - uint32_t rle_packet_size = 1; - - rle_packet_size += (src_ptr[0] & 0x80) ? bytes_per_pixel : (bytes_per_pixel * rle_count); - if ((rle_packet_size > src_bytes_left) || (pixel_count + rle_count) > row_width) - return D3DXERR_INVALIDDATA; - - if (src_ptr[0] & 0x80) - { - uint32_t i; - - for (i = 0; i < rle_count; ++i) - memcpy(&dst_row[(pixel_count + i) * bytes_per_pixel], src_ptr + 1, bytes_per_pixel); - } - else - { - memcpy(&dst_row[pixel_count * bytes_per_pixel], src_ptr + 1, rle_packet_size - 1); - } - - src_ptr += rle_packet_size; - src_bytes_left -= rle_packet_size; - pixel_count += rle_count; - if (!src_bytes_left && pixel_count != row_width) - return D3DXERR_INVALIDDATA; - } - - *src = src_ptr; - return D3D_OK; -} - -struct d3dx_color_key; -static 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, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key, - const PALETTEENTRY *palette); -static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, - struct d3dx_image *image) -{ - const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(image->format); - const struct tga_header *header = (const struct tga_header *)src_data; - const BOOL right_to_left = !!(header->image_descriptor & TGA_IMAGE_RIGHTTOLEFT); - const BOOL bottom_to_top = !(header->image_descriptor & TGA_IMAGE_TOPTOBOTTOM); - const BOOL is_rle = !!(header->image_type & TGA_IMAGETYPE_RLE); - uint8_t *img_buf = NULL, *src_row = NULL; - uint32_t row_pitch, slice_pitch, i; - PALETTEENTRY *palette = NULL; - const uint8_t *src_pos; - HRESULT hr; - - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - /* File is too small. */ - if (!is_rle && (src_header_size + slice_pitch) > src_data_size) - return D3DXERR_INVALIDDATA; - - if (image->format == D3DX_PIXEL_FORMAT_P8_UINT) - { - const uint8_t *src_palette = ((const uint8_t *)src_data) + sizeof(*header) + header->id_length; - const struct volume image_map_size = { header->color_map_length, 1, 1 }; - uint32_t src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch; - const struct pixel_format_desc *src_desc, *dst_desc; - - if (!(palette = malloc(sizeof(*palette) * 256))) - return E_OUTOFMEMORY; - - /* - * Convert from a TGA colormap to PALETTEENTRY. TGA is BGRA, - * PALETTEENTRY is RGBA. - */ - src_desc = get_d3dx_pixel_format_info(d3dx_get_tga_format_for_bpp(header->color_map_entrysize)); - hr = d3dx_calculate_pixels_size(src_desc->format, header->color_map_length, 1, &src_row_pitch, &src_slice_pitch); - if (FAILED(hr)) - goto exit; - - dst_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); - d3dx_calculate_pixels_size(dst_desc->format, 256, 1, &dst_row_pitch, &dst_slice_pitch); - convert_argb_pixels(src_palette, src_row_pitch, src_slice_pitch, &image_map_size, src_desc, (BYTE *)palette, - dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, NULL, NULL); - - /* Initialize unused palette entries to 0xff. */ - if (header->color_map_length < 256) - memset(&palette[header->color_map_length], 0xff, sizeof(*palette) * (256 - header->color_map_length)); - } - - if (!is_rle && !bottom_to_top && !right_to_left) - { - image->pixels = (uint8_t *)src_data + src_header_size; - image->image_palette = image->palette = palette; - return D3D_OK; - } - - if (!(img_buf = malloc(slice_pitch))) - { - hr = E_OUTOFMEMORY; - goto exit; - } - - /* Allocate an extra row to use as a temporary buffer. */ - if (is_rle) - { - if (!(src_row = malloc(row_pitch))) - { - hr = E_OUTOFMEMORY; - goto exit; - } - } - - src_pos = (const uint8_t *)src_data + src_header_size; - for (i = 0; i < image->size.height; ++i) - { - const uint32_t dst_row_idx = bottom_to_top ? (image->size.height - i - 1) : i; - uint8_t *dst_row = img_buf + (dst_row_idx * row_pitch); - - if (is_rle) - { - hr = d3dx_image_tga_rle_decode_row(&src_pos, src_data_size - (src_pos - (const uint8_t *)src_data), - image->size.width, fmt_desc->bytes_per_pixel, src_row); - if (FAILED(hr)) - goto exit; - } - else - { - src_row = (uint8_t *)src_pos; - src_pos += row_pitch; - } - - if (right_to_left) - { - const uint8_t *src_pixel = &src_row[((image->size.width - 1)) * fmt_desc->bytes_per_pixel]; - uint8_t *dst_pixel = dst_row; - uint32_t j; - - for (j = 0; j < image->size.width; ++j) - { - memcpy(dst_pixel, src_pixel, fmt_desc->bytes_per_pixel); - src_pixel -= fmt_desc->bytes_per_pixel; - dst_pixel += fmt_desc->bytes_per_pixel; - } - } - else - { - memcpy(dst_row, src_row, row_pitch); - } - } - - image->image_buf = image->pixels = img_buf; - image->image_palette = image->palette = palette; - -exit: - if (is_rle) - free(src_row); - if (img_buf && (image->image_buf != img_buf)) - free(img_buf); - if (palette && (image->image_palette != palette)) - free(palette); - - return hr; -} - -static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, - uint32_t flags) -{ - const struct tga_header *header = (const struct tga_header *)src_data; - uint32_t expected_header_size = sizeof(*header); - - if (src_data_size < sizeof(*header)) - return D3DXERR_INVALIDDATA; - - expected_header_size += header->id_length; - expected_header_size += header->color_map_length * ((header->color_map_entrysize + 7) / CHAR_BIT); - if (src_data_size < expected_header_size) - return D3DXERR_INVALIDDATA; - - if (header->color_map_type && ((header->color_map_type > 1) || (!header->color_map_length) - || (d3dx_get_tga_format_for_bpp(header->color_map_entrysize) == D3DX_PIXEL_FORMAT_COUNT))) - return D3DXERR_INVALIDDATA; - - switch (header->image_type & TGA_IMAGETYPE_MASK) - { - case TGA_IMAGETYPE_COLORMAPPED: - if (header->depth != 8 || !header->color_map_type) - return D3DXERR_INVALIDDATA; - image->format = D3DX_PIXEL_FORMAT_P8_UINT; - break; - - case TGA_IMAGETYPE_TRUECOLOR: - if ((image->format = d3dx_get_tga_format_for_bpp(header->depth)) == D3DX_PIXEL_FORMAT_COUNT) - return D3DXERR_INVALIDDATA; - break; - - case TGA_IMAGETYPE_GRAYSCALE: - if (header->depth != 8) - return D3DXERR_INVALIDDATA; - image->format = D3DX_PIXEL_FORMAT_L8_UNORM; - break; - - default: - return D3DXERR_INVALIDDATA; - } - - set_volume_struct(&image->size, header->width, header->height, 1); - image->mip_levels = 1; - image->layer_count = 1; - image->resource_type = D3DX_RESOURCE_TYPE_TEXTURE_2D; - image->image_file_format = D3DX_IMAGE_FILE_FORMAT_TGA; - - if (!(flags & D3DX_IMAGE_INFO_ONLY)) - return d3dx_image_tga_decode(src_data, src_data_size, expected_header_size, image); - - return D3D_OK; -} - -HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, - uint32_t starting_mip_level, uint32_t flags) -{ - enum d3dx_image_file_format iff = D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD; - HRESULT hr; - - if (!src_data || !src_data_size || !image) - return D3DERR_INVALIDCALL; - - memset(image, 0, sizeof(*image)); - if (!d3dx_get_image_file_format_from_file_signature(src_data, src_data_size, &iff)) - { - uint32_t src_image_size = src_data_size; - const void *src_image = src_data; - - if (convert_dib_to_bmp(&src_image, &src_image_size)) - { - hr = d3dx_image_init(src_image, src_image_size, image, starting_mip_level, flags); - free((void *)src_image); - if (SUCCEEDED(hr)) - image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DIB; - return hr; - } - - /* Last resort, try TGA. */ - return d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); - } - - switch (iff) - { - case D3DX_IMAGE_FILE_FORMAT_BMP: - case D3DX_IMAGE_FILE_FORMAT_JPG: - case D3DX_IMAGE_FILE_FORMAT_PNG: - hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, iff, flags); - break; - - case D3DX_IMAGE_FILE_FORMAT_DDS: - hr = d3dx_initialize_image_from_dds(src_data, src_data_size, image, starting_mip_level); - break; - - case D3DX_IMAGE_FILE_FORMAT_PPM: - case D3DX_IMAGE_FILE_FORMAT_HDR: - case D3DX_IMAGE_FILE_FORMAT_PFM: - WARN("Unsupported file format %s.\n", debug_d3dx_image_file_format(iff)); - hr = E_NOTIMPL; - break; - - case D3DX_IMAGE_FILE_FORMAT_FORCE_DWORD: - ERR("Unrecognized file format.\n"); - hr = D3DXERR_INVALIDDATA; - break; - - default: - assert(0); - return E_FAIL; - } - - return hr; -} - -void d3dx_image_cleanup(struct d3dx_image *image) -{ - free(image->image_buf); - free(image->image_palette); -} - -HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t layer, uint32_t mip_level, - struct d3dx_pixels *pixels) -{ - struct volume mip_level_size = image->size; - const BYTE *pixels_ptr = image->pixels; - uint32_t row_pitch, slice_pitch, i; - RECT unaligned_rect; - HRESULT hr = S_OK; - - if (mip_level >= image->mip_levels) - { - ERR("Tried to retrieve mip level %u, but image only has %u mip levels.\n", mip_level, image->mip_levels); - return E_FAIL; - } - - if (layer >= image->layer_count) - { - ERR("Tried to retrieve layer %u, but image only has %u layers.\n", layer, image->layer_count); - return E_FAIL; - } - - slice_pitch = row_pitch = 0; - for (i = 0; i < image->mip_levels; i++) - { - hr = d3dx_calculate_pixels_size(image->format, mip_level_size.width, mip_level_size.height, &row_pitch, &slice_pitch); - if (FAILED(hr)) - return hr; - - if (i == mip_level) - break; - - pixels_ptr += slice_pitch * mip_level_size.depth; - d3dx_get_next_mip_level_size(&mip_level_size); - } - - pixels_ptr += (layer * image->layer_pitch); - SetRect(&unaligned_rect, 0, 0, mip_level_size.width, mip_level_size.height); - set_d3dx_pixels(pixels, pixels_ptr, row_pitch, slice_pitch, image->palette, mip_level_size.width, - mip_level_size.height, mip_level_size.depth, &unaligned_rect); - - return D3D_OK; -} - -void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) -{ - info->ImageFileFormat = (D3DXIMAGE_FILEFORMAT)image->image_file_format; - info->Width = image->size.width; - info->Height = image->size.height; - info->Depth = image->size.depth; - info->MipLevels = image->mip_levels; - switch (image->format) - { - case D3DX_PIXEL_FORMAT_P1_UINT: - case D3DX_PIXEL_FORMAT_P2_UINT: - case D3DX_PIXEL_FORMAT_P4_UINT: - info->Format = D3DFMT_P8; - break; - - case D3DX_PIXEL_FORMAT_R16G16B16_UNORM: - info->Format = D3DFMT_A16B16G16R16; - break; - - case D3DX_PIXEL_FORMAT_B8G8R8_UNORM: - if (info->ImageFileFormat == D3DXIFF_PNG || info->ImageFileFormat == D3DXIFF_JPG) - info->Format = D3DFMT_X8R8G8B8; - else - info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); - break; - - default: - info->Format = d3dformat_from_d3dx_pixel_format_id(image->format); - break; - } - if (image->resource_type == D3DX_RESOURCE_TYPE_TEXTURE_3D) - info->ResourceType = D3DRTYPE_VOLUMETEXTURE; - else if (image->resource_type == D3DX_RESOURCE_TYPE_CUBE_TEXTURE) - info->ResourceType = D3DRTYPE_CUBETEXTURE; - else - info->ResourceType = D3DRTYPE_TEXTURE; -} - -/************************************************************ - * D3DXGetImageInfoFromFileInMemory - * - * Fills a D3DXIMAGE_INFO structure with info about an image - * - * PARAMS - * data [I] pointer to the image file data - * datasize [I] size of the passed data - * info [O] pointer to the destination structure - * - * RETURNS - * Success: D3D_OK, if info is not NULL and data and datasize make up a valid image file or - * if info is NULL and data and datasize are not NULL - * Failure: D3DXERR_INVALIDDATA, if data is no valid image file and datasize and info are not NULL - * D3DERR_INVALIDCALL, if data is NULL or - * if datasize is 0 - * - * NOTES - * datasize may be bigger than the actual file size - * - */ -HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize, D3DXIMAGE_INFO *info) -{ - struct d3dx_image image; - HRESULT hr; - - TRACE("(%p, %d, %p)\n", data, datasize, info); - - if (!data || !datasize) - return D3DERR_INVALIDCALL; - - if (!info) - return D3D_OK; - - hr = d3dx_image_init(data, datasize, &image, 0, D3DX_IMAGE_INFO_ONLY); - if (FAILED(hr)) { - TRACE("Invalid or unsupported image file\n"); - return D3DXERR_INVALIDDATA; - } - - d3dximage_info_from_d3dx_image(info, &image); - return D3D_OK; -} - -/************************************************************ - * D3DXGetImageInfoFromFile - * - * RETURNS - * Success: D3D_OK, if we successfully load a valid image file or - * if we successfully load a file which is no valid image and info is NULL - * Failure: D3DXERR_INVALIDDATA, if we fail to load file or - * if file is not a valid image file and info is not NULL - * D3DERR_INVALIDCALL, if file is NULL - * - */ -HRESULT WINAPI D3DXGetImageInfoFromFileA(const char *file, D3DXIMAGE_INFO *info) -{ - WCHAR *widename; - HRESULT hr; - int strlength; - - TRACE("file %s, info %p.\n", debugstr_a(file), info); - - if( !file ) return D3DERR_INVALIDCALL; - - strlength = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); - widename = malloc(strlength * sizeof(*widename)); - MultiByteToWideChar(CP_ACP, 0, file, -1, widename, strlength); - - hr = D3DXGetImageInfoFromFileW(widename, info); - free(widename); - - return hr; -} - -HRESULT WINAPI D3DXGetImageInfoFromFileW(const WCHAR *file, D3DXIMAGE_INFO *info) -{ - void *buffer; - HRESULT hr; - DWORD size; - - TRACE("file %s, info %p.\n", debugstr_w(file), info); - - if (!file) - return D3DERR_INVALIDCALL; - - if (FAILED(map_view_of_file(file, &buffer, &size))) - return D3DXERR_INVALIDDATA; - - hr = D3DXGetImageInfoFromFileInMemory(buffer, size, info); - UnmapViewOfFile(buffer); - - return hr; -} - -/************************************************************ - * D3DXGetImageInfoFromResource - * - * RETURNS - * Success: D3D_OK, if resource is a valid image file - * Failure: D3DXERR_INVALIDDATA, if resource is no valid image file or NULL or - * if we fail to load resource - * - */ -HRESULT WINAPI D3DXGetImageInfoFromResourceA(HMODULE module, const char *resource, D3DXIMAGE_INFO *info) -{ - HRSRC resinfo; - void *buffer; - DWORD size; - - TRACE("module %p, resource %s, info %p.\n", module, debugstr_a(resource), info); - - if (!(resinfo = FindResourceA(module, resource, (const char *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceA(module, resource, (const char *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) - return D3DXERR_INVALIDDATA; - - return D3DXGetImageInfoFromFileInMemory(buffer, size, info); -} - -HRESULT WINAPI D3DXGetImageInfoFromResourceW(HMODULE module, const WCHAR *resource, D3DXIMAGE_INFO *info) -{ - HRSRC resinfo; - void *buffer; - DWORD size; - - TRACE("module %p, resource %s, info %p.\n", module, debugstr_w(resource), info); - - if (!(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceW(module, resource, (const WCHAR *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(module, resinfo, &buffer, &size))) - return D3DXERR_INVALIDDATA; - - return D3DXGetImageInfoFromFileInMemory(buffer, size, info); -} - -static HRESULT d3dx_load_surface_from_memory(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const void *src_memory, - enum d3dx_pixel_format_id src_format, uint32_t src_pitch, const PALETTEENTRY *src_palette, const RECT *src_rect, - DWORD filter, D3DCOLOR color_key) -{ - const struct pixel_format_desc *src_desc, *dst_desc; - struct d3dx_pixels src_pixels, dst_pixels; - RECT dst_rect_tmp, dst_rect_aligned; - IDirect3DSurface9 *surface; - D3DLOCKED_RECT lock_rect; - D3DSURFACE_DESC desc; - HRESULT hr; - - IDirect3DSurface9_GetDesc(dst_surface, &desc); - if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) - { - TRACE("Multisampled destination surface, doing nothing.\n"); - return D3D_OK; - } - - dst_desc = get_format_info(desc.Format); - if (!dst_rect) - { - SetRect(&dst_rect_tmp, 0, 0, desc.Width, desc.Height); - dst_rect = &dst_rect_tmp; - } - else - { - if (dst_rect->left > dst_rect->right || dst_rect->right > desc.Width - || dst_rect->top > dst_rect->bottom || dst_rect->bottom > desc.Height - || dst_rect->left < 0 || dst_rect->top < 0) - { - WARN("Invalid dst_rect specified.\n"); - return D3DERR_INVALIDCALL; - } - if (dst_rect->left == dst_rect->right || dst_rect->top == dst_rect->bottom) - { - WARN("Empty dst_rect specified.\n"); - return D3D_OK; - } - } - - src_desc = get_d3dx_pixel_format_info(src_format); - hr = d3dx_pixels_init(src_memory, src_pitch, 0, src_palette, src_desc->format, - src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1, &src_pixels); - if (FAILED(hr)) - return hr; - - get_aligned_rect(dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, desc.Width, desc.Height, - dst_desc, &dst_rect_aligned); - if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lock_rect, &surface, TRUE))) - return hr; - - set_d3dx_pixels(&dst_pixels, lock_rect.pBits, lock_rect.Pitch, 0, dst_palette, - (dst_rect_aligned.right - dst_rect_aligned.left), (dst_rect_aligned.bottom - dst_rect_aligned.top), 1, - dst_rect); - OffsetRect(&dst_pixels.unaligned_rect, -dst_rect_aligned.left, -dst_rect_aligned.top); - - if (FAILED(hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_desc, &src_pixels, src_desc, filter, color_key))) - { - unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); - return hr; - } - - return unlock_surface(dst_surface, &dst_rect_aligned, surface, TRUE); -} - -/************************************************************ - * D3DXLoadSurfaceFromFileInMemory - * - * Loads data from a given buffer into a surface and fills a given - * D3DXIMAGE_INFO structure with info about the source data. - * - * PARAMS - * pDestSurface [I] pointer to the surface - * pDestPalette [I] palette to use - * pDestRect [I] to be filled area of the surface - * pSrcData [I] pointer to the source data - * SrcDataSize [I] size of the source data in bytes - * pSrcRect [I] area of the source data to load - * dwFilter [I] filter to apply on stretching - * Colorkey [I] colorkey - * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure - * - * RETURNS - * Success: D3D_OK - * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL - * D3DXERR_INVALIDDATA, if pSrcData is no valid image file - * - */ -HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, - const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, - const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) -{ - struct d3dx_pixels pixels = { 0 }; - struct d3dx_image image; - D3DXIMAGE_INFO img_info; - RECT src_rect; - HRESULT hr; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize, - wine_dbgstr_rect(pSrcRect), dwFilter, Colorkey, pSrcInfo); - - if (!pDestSurface || !pSrcData || !SrcDataSize) - return D3DERR_INVALIDCALL; - - if (FAILED(hr = d3dx9_handle_load_filter(&dwFilter))) - return hr; - - hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0, 0); - if (FAILED(hr)) - return D3DXERR_INVALIDDATA; - - d3dximage_info_from_d3dx_image(&img_info, &image); - if (pSrcRect) - src_rect = *pSrcRect; - else - SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height); - - hr = d3dx_image_get_pixels(&image, 0, 0, &pixels); - if (FAILED(hr)) - goto exit; - - hr = d3dx_load_surface_from_memory(pDestSurface, pDestPalette, pDestRect, pixels.data, image.format, pixels.row_pitch, - pixels.palette, &src_rect, dwFilter, Colorkey); - if (SUCCEEDED(hr) && pSrcInfo) - *pSrcInfo = img_info; - -exit: - d3dx_image_cleanup(&image); - return FAILED(hr) ? D3DXERR_INVALIDDATA : D3D_OK; -} - -HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const char *src_file, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - WCHAR *src_file_w; - HRESULT hr; - int strlength; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_a(src_file), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!src_file || !dst_surface) - return D3DERR_INVALIDCALL; - - strlength = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0); - src_file_w = malloc(strlength * sizeof(*src_file_w)); - MultiByteToWideChar(CP_ACP, 0, src_file, -1, src_file_w, strlength); - - hr = D3DXLoadSurfaceFromFileW(dst_surface, dst_palette, dst_rect, - src_file_w, src_rect, filter, color_key, src_info); - free(src_file_w); - - return hr; -} - -HRESULT WINAPI D3DXLoadSurfaceFromFileW(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, const WCHAR *src_file, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - DWORD data_size; - void *data; - HRESULT hr; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_w(src_file), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!src_file || !dst_surface) - return D3DERR_INVALIDCALL; - - if (FAILED(map_view_of_file(src_file, &data, &data_size))) - return D3DXERR_INVALIDDATA; - - hr = D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, - data, data_size, src_rect, filter, color_key, src_info); - UnmapViewOfFile(data); - - return hr; -} - -HRESULT WINAPI D3DXLoadSurfaceFromResourceA(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const char *resource, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - DWORD data_size; - HRSRC resinfo; - void *data; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_a(resource), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!dst_surface) - return D3DERR_INVALIDCALL; - - if (!(resinfo = FindResourceA(src_module, resource, (const char *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceA(src_module, resource, (const char *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) - return D3DXERR_INVALIDDATA; - - return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, - data, data_size, src_rect, filter, color_key, src_info); -} - -HRESULT WINAPI D3DXLoadSurfaceFromResourceW(IDirect3DSurface9 *dst_surface, - const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const WCHAR *resource, - const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) -{ - DWORD data_size; - HRSRC resinfo; - void *data; - - TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " - "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", - dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_w(resource), - wine_dbgstr_rect(src_rect), filter, color_key, src_info); - - if (!dst_surface) - return D3DERR_INVALIDCALL; - - if (!(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_RCDATA)) - /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ - && !(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_BITMAP))) - return D3DXERR_INVALIDDATA; - - if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) - return D3DXERR_INVALIDDATA; - - return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, - data, data_size, src_rect, filter, color_key, src_info); -} - - -/************************************************************ - * helper functions for D3DXLoadSurfaceFromMemory - */ -struct argb_conversion_info -{ - const struct pixel_format_desc *srcformat; - const struct pixel_format_desc *destformat; - DWORD srcshift[4], destshift[4]; - DWORD srcmask[4], destmask[4]; - BOOL process_channel[4]; - DWORD channelmask; -}; - -static void init_argb_conversion_info(const struct pixel_format_desc *srcformat, const struct pixel_format_desc *destformat, struct argb_conversion_info *info) -{ - UINT i; - ZeroMemory(info->process_channel, 4 * sizeof(BOOL)); - info->channelmask = 0; - - info->srcformat = srcformat; - info->destformat = destformat; - - for(i = 0;i < 4;i++) { - /* srcshift is used to extract the _relevant_ components */ - info->srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0); - - /* destshift is used to move the components to the correct position */ - info->destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0); - - info->srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i]; - info->destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i]; - - /* channelmask specifies bits which aren't used in the source format but in the destination one */ - if(destformat->bits[i]) { - if(srcformat->bits[i]) info->process_channel[i] = TRUE; - else info->channelmask |= info->destmask[i]; - } - } -} - -/************************************************************ - * get_relevant_argb_components - * - * 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, const BYTE *col, DWORD *out) -{ - 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; - } -} - -static float d3dx_clamp(float value, float min_value, float max_value) -{ - if (isnan(value)) - return max_value; - return value < min_value ? min_value : value > max_value ? max_value : value; -} + return unlock_surface(dst_surface, &dst_rect_aligned, surface, TRUE); +}
/************************************************************ - * make_argb_color + * D3DXLoadSurfaceFromFileInMemory * - * Recombines the output of get_relevant_argb_components and converts - * it to the destination format. - */ -static DWORD make_argb_color(const struct argb_conversion_info *info, const DWORD *in) -{ - UINT i; - DWORD val = 0; - - for(i = 0;i < 4;i++) { - if(info->process_channel[i]) { - /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */ - signed int shift; - for(shift = info->destshift[i]; shift > info->destformat->shift[i]; shift -= info->srcformat->bits[i]) val |= in[i] << shift; - val |= (in[i] >> (info->destformat->shift[i] - shift)) << info->destformat->shift[i]; - } - } - val |= info->channelmask; /* new channels are set to their maximal value */ - return val; -} - -static enum range get_range_for_component_type(enum component_type type) -{ - switch (type) - { - case CTYPE_SNORM: - return RANGE_SNORM; - - case CTYPE_LUMA: - case CTYPE_INDEX: - case CTYPE_UNORM: - return RANGE_UNORM; - - case CTYPE_EMPTY: - case CTYPE_FLOAT: - return RANGE_FULL; - - default: - assert(0); - return RANGE_FULL; - } -} - -/* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */ -void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, const PALETTEENTRY *palette, - struct d3dx_color *dst) -{ - DWORD mask, tmp; - unsigned int c; - - dst->rgb_range = get_range_for_component_type(format->rgb_type); - dst->a_range = get_range_for_component_type(format->a_type); - for (c = 0; c < 4; ++c) - { - const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; - static const unsigned int component_offsets[4] = {3, 0, 1, 2}; - float *dst_component = &dst->value.x + component_offsets[c]; - - if (format->bits[c]) - { - mask = ~0u >> (32 - format->bits[c]); - - memcpy(&tmp, src + format->shift[c] / 8, - min(sizeof(DWORD), (format->shift[c] % 8 + format->bits[c] + 7) / 8)); - tmp = (tmp >> (format->shift[c] % 8)) & mask; - - switch (dst_ctype) - { - case CTYPE_FLOAT: - if (format->bits[c] == 16) - *dst_component = float_16_to_32(tmp); - else - *dst_component = *(float *)&tmp; - break; - - case CTYPE_INDEX: - *dst_component = (&palette[tmp].peRed)[component_offsets[c]] / 255.0f; - break; - - case CTYPE_LUMA: - case CTYPE_UNORM: - *dst_component = (float)tmp / mask; - break; - - case CTYPE_SNORM: - { - const uint32_t sign_bit = (1u << (format->bits[c] - 1)); - uint32_t tmp_extended = (tmp & sign_bit) ? (tmp | ~(sign_bit - 1)) : tmp; - - /* - * In order to clamp to an even range, we need to ignore - * the maximum negative value. - */ - if (tmp == sign_bit) - tmp_extended |= 1; - - *dst_component = (float)(((int32_t)tmp_extended)) / (sign_bit - 1); - break; - } - - default: - break; - } - } - else if (dst_ctype == CTYPE_LUMA) - { - assert(format->bits[1]); - *dst_component = dst->value.x; - } - else - { - *dst_component = 1.0f; - } - } -} - -/* It doesn't work for components bigger than 32 bits. */ -void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) -{ - DWORD v, mask32; - unsigned int c, i; - - memset(dst, 0, format->bytes_per_pixel); - - for (c = 0; c < 4; ++c) - { - const enum component_type dst_ctype = !c ? format->a_type : format->rgb_type; - static const unsigned int component_offsets[4] = {3, 0, 1, 2}; - const float src_component = *(&src->value.x + component_offsets[c]); - const enum range src_range = !c ? src->a_range : src->rgb_range; - - if (!format->bits[c]) - continue; - - mask32 = ~0u >> (32 - format->bits[c]); - - switch (dst_ctype) - { - case CTYPE_FLOAT: - if (format->bits[c] == 16) - v = float_32_to_16(src_component); - else - v = *(DWORD *)&src_component; - break; - - case CTYPE_LUMA: - { - float val = src->value.x * 0.2125f + src->value.y * 0.7154f + src->value.z * 0.0721f; - - if (src_range == RANGE_SNORM) - val = (val + 1.0f) / 2.0f; - - v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; - break; - } - - case CTYPE_UNORM: - { - float val = src_component; - - if (src_range == RANGE_SNORM) - val = (val + 1.0f) / 2.0f; - - v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; - break; - } - - case CTYPE_SNORM: - { - const uint32_t max_value = (1u << (format->bits[c] - 1)) - 1; - float val = src_component; - - if (src_range == RANGE_UNORM) - val = (val * 2.0f) - 1.0f; - - v = d3dx_clamp(val, -1.0f, 1.0f) * max_value + 0.5f; - break; - } - - /* We shouldn't be trying to output to CTYPE_INDEX. */ - case CTYPE_INDEX: - assert(0); - break; - - default: - v = 0; - break; - } - - for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) - { - BYTE mask, byte; - - if (format->shift[c] > i) - { - mask = mask32 << (format->shift[c] - i); - byte = (v << (format->shift[c] - i)) & mask; - } - else - { - mask = mask32 >> (i - format->shift[c]); - byte = (v >> (i - format->shift[c])) & mask; - } - dst[i / 8] |= byte; - } - } -} - -struct d3dx_color_key -{ - uint8_t color_key_min[4]; - uint8_t color_key_max[4]; -}; - -static const char *debug_d3dx_color_key(const struct d3dx_color_key *color_key) -{ - if (!color_key) - return "(null)"; - return wine_dbg_sprintf("(0x%02x->0x%02x)-(0x%02x->0x%02x)-(0x%02x->0x%02x)-(0x%02x->0x%02x)", - color_key->color_key_min[0], color_key->color_key_max[0], - color_key->color_key_min[1], color_key->color_key_max[1], - color_key->color_key_min[2], color_key->color_key_max[2], - color_key->color_key_min[3], color_key->color_key_max[3]); -} - -static void d3dx_init_color_key(const struct pixel_format_desc *src_fmt, uint32_t color_key, - struct d3dx_color_key *color_key_out) -{ - unsigned int i; - - for (i = 0; i < 4; ++i) - { - const enum component_type src_ctype = !i ? src_fmt->a_type : src_fmt->rgb_type; - const uint8_t channel_bits = (src_ctype == CTYPE_LUMA) ? src_fmt->bits[1] : src_fmt->bits[i]; - const uint8_t ck_channel = (color_key >> (24 - (i * 8))) & 0xff; - float slop, channel_conv, unique_values; - - if (!channel_bits) - { - color_key_out->color_key_min[i] = 0x00; - color_key_out->color_key_max[i] = 0xff; - continue; - } - - /* - * If the source format channel can represent all unique channel - * values in the color key, no extra processing is necessary. - */ - if (src_ctype == CTYPE_FLOAT || (src_ctype == CTYPE_SNORM && channel_bits > 8) - || (src_ctype != CTYPE_SNORM && channel_bits >= 8)) - { - color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = ck_channel; - continue; - } - - channel_conv = ck_channel / 255.0f; - if (src_ctype == CTYPE_SNORM) - { - const uint32_t max_value = (1u << (channel_bits - 1)) - 1; - - unique_values = (1u << channel_bits) - 2; - channel_conv = (channel_conv * 2.0f) - 1.0f; - channel_conv = rintf(channel_conv * max_value) / max_value; - channel_conv = (channel_conv + 1.0f) / 2.0f; - } - else - { - unique_values = (1u << channel_bits) - 1; - channel_conv = rintf(channel_conv * unique_values) / unique_values; - } - - channel_conv = channel_conv * 255.0f; - slop = (255.0f - unique_values) / unique_values / 2.0f; - color_key_out->color_key_min[i] = rintf(d3dx_clamp(channel_conv - slop, 0.0f, 255.0f)); - color_key_out->color_key_max[i] = rintf(d3dx_clamp(channel_conv + slop, 0.0f, 255.0f)); - } -} - -/************************************************************ - * copy_pixels + * Loads data from a given buffer into a surface and fills a given + * D3DXIMAGE_INFO structure with info about the source data. * - * Copies the source buffer to the destination buffer. - * Works for any pixel format. - * The source and the destination must be block-aligned. - */ -static void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, - const struct pixel_format_desc *format) -{ - 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; - - for (slice = 0; slice < size->depth; slice++) - { - src_addr = src + slice * src_slice_pitch; - dst_addr = dst + slice * dst_slice_pitch; - - for (row = 0; row < row_count; row++) - { - memcpy(dst_addr, src_addr, row_block_count * format->block_byte_count); - src_addr += src_row_pitch; - dst_addr += dst_row_pitch; - } - } -} - -static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format_desc *src_fmt, - uint8_t *dst_ptr, const struct pixel_format_desc *dst_fmt, const PALETTEENTRY *palette, - struct argb_conversion_info *conv_info, const struct d3dx_color_key *color_key, - const struct pixel_format_desc *ck_format, struct argb_conversion_info *ck_conv_info) -{ - unsigned int i; - - if (format_types_match(src_fmt, dst_fmt) && src_fmt->bytes_per_pixel <= 4 && dst_fmt->bytes_per_pixel <= 4) - { - DWORD channels[4]; - DWORD val; - - 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, src_ptr, channels); - ck_pixel = make_argb_color(ck_conv_info, channels); - for (i = 0; i < 4; ++i) - { - const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff; - - if ((ck_channel < color_key->color_key_min[i]) || (ck_channel > color_key->color_key_max[i])) - break; - } - if (i == 4) - val = 0; - } - memcpy(dst_ptr, &val, dst_fmt->bytes_per_pixel); - } - else - { - struct d3dx_color color, tmp; - - format_to_d3dx_color(src_fmt, src_ptr, palette, &color); - tmp = color; - - if (color_key) - { - DWORD ck_pixel = 0; - - format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); - for (i = 0; i < 4; ++i) - { - const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff; - - if ((ck_channel < color_key->color_key_min[i]) || (ck_channel > color_key->color_key_max[i])) - break; - } - if (i == 4) - tmp.value.x = tmp.value.y = tmp.value.z = tmp.value.w = 0.0f; - } - - color = tmp; - format_from_d3dx_color(dst_fmt, &color, dst_ptr); - } -} - -/************************************************************ - * convert_argb_pixels + * PARAMS + * pDestSurface [I] pointer to the surface + * pDestPalette [I] palette to use + * pDestRect [I] to be filled area of the surface + * pSrcData [I] pointer to the source data + * SrcDataSize [I] size of the source data in bytes + * pSrcRect [I] area of the source data to load + * dwFilter [I] filter to apply on stretching + * Colorkey [I] colorkey + * pSrcInfo [O] pointer to a D3DXIMAGE_INFO structure * - * Copies the source buffer to the destination buffer, performing - * any necessary format conversion and color keying. - * Pixels outsize the source rect are blacked out. - */ -static 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, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key, - const PALETTEENTRY *palette) -{ - /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; - struct argb_conversion_info conv_info, ck_conv_info; - UINT min_width, min_height, min_depth; - UINT x, y, z; - - TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " - "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %s, palette %p.\n", - src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, - dst_format, debug_d3dx_color_key(color_key), palette); - - init_argb_conversion_info(src_format, dst_format, &conv_info); - - min_width = min(src_size->width, dst_size->width); - min_height = min(src_size->height, dst_size->height); - min_depth = min(src_size->depth, dst_size->depth); - - if (color_key) - init_argb_conversion_info(src_format, ck_format, &ck_conv_info); - - for (z = 0; z < min_depth; z++) { - const BYTE *src_slice_ptr = src + z * src_slice_pitch; - BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; - - for (y = 0; y < min_height; y++) { - const BYTE *src_ptr = src_slice_ptr + y * src_row_pitch; - BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; - - for (x = 0; x < min_width; x++) { - convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, - &conv_info, color_key, ck_format, &ck_conv_info); - - src_ptr += src_format->bytes_per_pixel; - dst_ptr += dst_format->bytes_per_pixel; - } - - if (src_size->width < dst_size->width) /* black out remaining pixels */ - memset(dst_ptr, 0, dst_format->bytes_per_pixel * (dst_size->width - src_size->width)); - } - - if (src_size->height < dst_size->height) /* black out remaining pixels */ - memset(dst + src_size->height * dst_row_pitch, 0, dst_row_pitch * (dst_size->height - src_size->height)); - } - if (src_size->depth < dst_size->depth) /* black out remaining pixels */ - memset(dst + src_size->depth * dst_slice_pitch, 0, dst_slice_pitch * (dst_size->depth - src_size->depth)); -} - -/************************************************************ - * point_filter_argb_pixels + * RETURNS + * Success: D3D_OK + * Failure: D3DERR_INVALIDCALL, if pDestSurface, pSrcData or SrcDataSize is NULL + * D3DXERR_INVALIDDATA, if pSrcData is no valid image file * - * Copies the source buffer to the destination buffer, performing - * any necessary format conversion, color keying and stretching - * using a point filter. */ -static 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 struct volume *dst_size, const struct pixel_format_desc *dst_format, - const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) +HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface, + const PALETTEENTRY *pDestPalette, const RECT *pDestRect, const void *pSrcData, UINT SrcDataSize, + const RECT *pSrcRect, DWORD dwFilter, D3DCOLOR Colorkey, D3DXIMAGE_INFO *pSrcInfo) { - /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; - struct argb_conversion_info conv_info, ck_conv_info; - UINT x, y, z; - - TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " - "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %s, palette %p.\n", - src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, - dst_format, debug_d3dx_color_key(color_key), palette); - - init_argb_conversion_info(src_format, dst_format, &conv_info); - - if (color_key) - init_argb_conversion_info(src_format, ck_format, &ck_conv_info); - - for (z = 0; z < dst_size->depth; z++) - { - BYTE *dst_slice_ptr = dst + z * dst_slice_pitch; - const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth); - - for (y = 0; y < dst_size->height; y++) - { - BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch; - const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height); - - for (x = 0; x < dst_size->width; x++) - { - const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel; - - convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, - &conv_info, color_key, ck_format, &ck_conv_info); - dst_ptr += dst_format->bytes_per_pixel; - } - } - } -} + struct d3dx_pixels pixels = { 0 }; + struct d3dx_image image; + D3DXIMAGE_INFO img_info; + RECT src_rect; + HRESULT hr;
-static HRESULT d3dx_pixels_decompress(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, - BOOL is_dst, void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, - const struct pixel_format_desc **out_desc) -{ - uint32_t uncompressed_slice_pitch, uncompressed_row_pitch, block_buf_row_pitch, block_width_mask, block_height_mask; - void (*decompress_bcn_block)(const void *src, void *dst, int dst_row_pitch); - const struct pixel_format_desc *uncompressed_desc = NULL; - const struct volume *size = &pixels->size; - BYTE *uncompressed_mem; - uint8_t block_buf[64]; - unsigned int x, y, z; - RECT aligned_rect; - - switch (desc->format) - { - case D3DX_PIXEL_FORMAT_DXT1_UNORM: - uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); - decompress_bcn_block = bcdec_bc1; - break; + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_data %p, src_data_size %u, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + pDestSurface, pDestPalette, wine_dbgstr_rect(pDestRect), pSrcData, SrcDataSize, + wine_dbgstr_rect(pSrcRect), dwFilter, Colorkey, pSrcInfo);
- case D3DX_PIXEL_FORMAT_DXT2_UNORM: - case D3DX_PIXEL_FORMAT_DXT3_UNORM: - uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); - decompress_bcn_block = bcdec_bc2; - break; + if (!pDestSurface || !pSrcData || !SrcDataSize) + return D3DERR_INVALIDCALL;
- case D3DX_PIXEL_FORMAT_DXT4_UNORM: - case D3DX_PIXEL_FORMAT_DXT5_UNORM: - uncompressed_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); - decompress_bcn_block = bcdec_bc3; - break; + if (FAILED(hr = d3dx9_handle_load_filter(&dwFilter))) + return hr;
- default: - FIXME("Unexpected compressed texture format %u.\n", desc->format); - return E_NOTIMPL; - } + hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0, 0); + if (FAILED(hr)) + return D3DXERR_INVALIDDATA;
- block_width_mask = desc->block_width - 1; - block_height_mask = desc->block_height - 1; - block_buf_row_pitch = desc->block_width * uncompressed_desc->bytes_per_pixel; - uncompressed_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; - uncompressed_slice_pitch = uncompressed_row_pitch * size->height; - if (!(uncompressed_mem = malloc(size->depth * uncompressed_slice_pitch))) - return E_OUTOFMEMORY; - - /* - * For compressed destination pixels, width/height will represent - * the entire set of compressed blocks our destination rectangle touches. - * If we're only updating a sub-area of any blocks, we need to decompress - * the pixels outside of the sub-area. - */ - if (is_dst) - { - SetRect(&aligned_rect, 0, 0, size->width, size->height); - - /* - * If our destination covers the entire set of blocks, no - * decompression needs to be done, just return the allocated memory. - */ - if (EqualRect(&aligned_rect, &pixels->unaligned_rect)) - goto exit; - } - /* - * For compressed source pixels, width/height will represent the size of - * the unaligned rectangle. I.e, if we have an 8x8 source with an - * unaligned rect of (2,2)-(6,6) our width/height will be 4. - */ + d3dximage_info_from_d3dx_image(&img_info, &image); + if (pSrcRect) + src_rect = *pSrcRect; else - { - SetRect(&aligned_rect, 0, 0, (pixels->unaligned_rect.right + block_width_mask) & ~block_width_mask, - (pixels->unaligned_rect.bottom + block_height_mask) & ~block_height_mask); - } - - TRACE("Decompressing pixels.\n"); - for (z = 0; z < size->depth; ++z) - { - const uint8_t *src_slice = &((const uint8_t *)pixels->data)[z * pixels->slice_pitch]; - uint8_t *dst_slice = &uncompressed_mem[z * uncompressed_slice_pitch]; + SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height);
- for (y = 0; y < aligned_rect.bottom; y += desc->block_height) - { - const uint8_t *src_ptr = &src_slice[(y / desc->block_height) * pixels->row_pitch]; + hr = d3dx_image_get_pixels(&image, 0, 0, &pixels); + if (FAILED(hr)) + goto exit;
- for (x = 0; x < aligned_rect.right; x += desc->block_width) - { - struct volume dst_block_size; - RECT src_rect, dst_rect; - uint8_t *dst_ptr; - - SetRect(&src_rect, x, y, x + desc->block_width, y + desc->block_height); - IntersectRect(&src_rect, &src_rect, &pixels->unaligned_rect); - dst_rect = src_rect; - OffsetRect(&dst_rect, -pixels->unaligned_rect.left, -pixels->unaligned_rect.top); - - set_volume_struct(&dst_block_size, dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top, 1); - dst_ptr = &dst_slice[(dst_rect.top * uncompressed_row_pitch)]; - dst_ptr += dst_rect.left * uncompressed_desc->bytes_per_pixel; - - if (dst_block_size.width != desc->block_width || dst_block_size.height != desc->block_height) - { - if (!is_dst) - { - unsigned int block_buf_offset; - - decompress_bcn_block(src_ptr, block_buf, block_buf_row_pitch); - block_buf_offset = (src_rect.top - y) * block_buf_row_pitch; - block_buf_offset += uncompressed_desc->bytes_per_pixel * (src_rect.left - x); - copy_pixels(&block_buf[block_buf_offset], block_buf_row_pitch, 0, dst_ptr, - uncompressed_row_pitch, 0, &dst_block_size, uncompressed_desc); - } - /* - * If this is the destination, we can just copy the whole - * block. It will be partially overwritten later. - */ - else - { - dst_ptr = &dst_slice[y * uncompressed_row_pitch + x * uncompressed_desc->bytes_per_pixel]; - decompress_bcn_block(src_ptr, dst_ptr, uncompressed_row_pitch); - } - - } - /* Full block copy. */ - else if (!is_dst) - { - decompress_bcn_block(src_ptr, dst_ptr, uncompressed_row_pitch); - } - src_ptr += desc->block_byte_count; - } - } - } + hr = d3dx_load_surface_from_memory(pDestSurface, pDestPalette, pDestRect, pixels.data, image.format, pixels.row_pitch, + pixels.palette, &src_rect, dwFilter, Colorkey); + if (SUCCEEDED(hr) && pSrcInfo) + *pSrcInfo = img_info;
exit: - *out_memory = uncompressed_mem; - *out_row_pitch = uncompressed_row_pitch; - *out_slice_pitch = uncompressed_slice_pitch; - *out_desc = uncompressed_desc; - - return S_OK; + d3dx_image_cleanup(&image); + return FAILED(hr) ? D3DXERR_INVALIDDATA : D3D_OK; }
-static HRESULT d3dx_pixels_unpack_index(struct d3dx_pixels *pixels, const struct pixel_format_desc *desc, - void **out_memory, uint32_t *out_row_pitch, uint32_t *out_slice_pitch, const struct pixel_format_desc **out_desc) +HRESULT WINAPI D3DXLoadSurfaceFromFileA(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const char *src_file, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) { - uint32_t x, y, z, unpacked_slice_pitch, unpacked_row_pitch; - const struct pixel_format_desc *unpacked_desc = NULL; - const struct volume *size = &pixels->size; - uint8_t *unpacked_mem; - uint8_t mask, shift; - - switch (desc->format) - { - case D3DX_PIXEL_FORMAT_P1_UINT: - case D3DX_PIXEL_FORMAT_P2_UINT: - case D3DX_PIXEL_FORMAT_P4_UINT: - unpacked_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_P8_UINT); - break; - - default: - FIXME("Unexpected format %u.\n", desc->format); - return E_NOTIMPL; - } - - unpacked_row_pitch = size->width * unpacked_desc->bytes_per_pixel; - unpacked_slice_pitch = unpacked_row_pitch * size->height; - if (!(unpacked_mem = malloc(size->depth * unpacked_slice_pitch))) - return E_OUTOFMEMORY; - - shift = 8 / desc->block_width; - mask = (1u << shift) - 1; - - TRACE("Unpacking pixels.\n"); - for (z = 0; z < size->depth; ++z) - { - const uint8_t *slice_data = (const uint8_t *)pixels->data + (pixels->slice_pitch * z); - - for (y = 0; y < size->height; ++y) - { - uint8_t *ptr = &unpacked_mem[(z * unpacked_slice_pitch) + (y * unpacked_row_pitch)]; - const uint8_t *row_data = slice_data + (pixels->row_pitch * y); - - for (x = 0; x < size->width; x += desc->block_width) - { - const uint8_t packed_data = *row_data; - unsigned int i; - - for (i = 0; i < desc->block_width; ++i) - { - const uint8_t cur_shift = ((desc->block_width - 1) - i) * shift; - - if (x + i >= size->width) - break; - ptr[i] = (packed_data >> cur_shift) & mask; - } - ptr += unpacked_desc->bytes_per_pixel * desc->block_width; - row_data++; - } - } - } - - *out_memory = unpacked_mem; - *out_row_pitch = unpacked_row_pitch; - *out_slice_pitch = unpacked_slice_pitch; - *out_desc = unpacked_desc; - - return S_OK; -} + WCHAR *src_file_w; + HRESULT hr; + int strlength;
-static void d3dx_compress_block(enum d3dx_pixel_format_id fmt, uint8_t *block_buf, void *dst_buf) -{ - switch (fmt) - { - case D3DX_PIXEL_FORMAT_DXT1_UNORM: - stb_compress_dxt_block(dst_buf, block_buf, FALSE, 0); - break; + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_a(src_file), + wine_dbgstr_rect(src_rect), filter, color_key, src_info);
- case D3DX_PIXEL_FORMAT_DXT2_UNORM: - case D3DX_PIXEL_FORMAT_DXT3_UNORM: - { - uint8_t *dst_data_offset = dst_buf; - unsigned int y; + if (!src_file || !dst_surface) + return D3DERR_INVALIDCALL;
- /* STB doesn't do DXT2/DXT3, we'll do the alpha part ourselves. */ - for (y = 0; y < 4; ++y) - { - uint8_t *tmp_row = &block_buf[y * 4 * 4]; - - dst_data_offset[0] = (tmp_row[7] & 0xf0); - dst_data_offset[0] |= (tmp_row[3] >> 4); - dst_data_offset[1] = (tmp_row[15] & 0xf0); - dst_data_offset[1] |= (tmp_row[11] >> 4); - - /* - * Set all alpha values to 0xff so they aren't considered during - * compression. This modifies the source data being passed in. - */ - tmp_row[3] = tmp_row[7] = tmp_row[11] = tmp_row[15] = 0xff; - dst_data_offset += 2; - } - stb_compress_dxt_block(dst_data_offset, block_buf, FALSE, 0); - break; - } + strlength = MultiByteToWideChar(CP_ACP, 0, src_file, -1, NULL, 0); + src_file_w = malloc(strlength * sizeof(*src_file_w)); + MultiByteToWideChar(CP_ACP, 0, src_file, -1, src_file_w, strlength);
- case D3DX_PIXEL_FORMAT_DXT4_UNORM: - case D3DX_PIXEL_FORMAT_DXT5_UNORM: - stb_compress_dxt_block(dst_buf, block_buf, TRUE, 0); - break; + hr = D3DXLoadSurfaceFromFileW(dst_surface, dst_palette, dst_rect, + src_file_w, src_rect, filter, color_key, src_info); + free(src_file_w);
- default: - assert(0); - break; - } + return hr; }
-/* - * Source data passed into this function is potentially modified (currently - * only in the case of DXT2/DXT3). As of now we only pass temporary buffers - * into this function, but this should be taken to account if used elsewhere - * outside of d3dx_load_pixels_from_pixels() in the future. - */ -static HRESULT d3dx_pixels_compress(struct d3dx_pixels *src_pixels, - const struct pixel_format_desc *src_desc, struct d3dx_pixels *dst_pixels, - const struct pixel_format_desc *dst_desc) +HRESULT WINAPI D3DXLoadSurfaceFromFileW(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const WCHAR *src_file, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) { - unsigned int x, y, z, block_buf_row_pitch; - uint8_t block_buf[64]; - - switch (dst_desc->format) - { - case D3DX_PIXEL_FORMAT_DXT1_UNORM: - case D3DX_PIXEL_FORMAT_DXT2_UNORM: - case D3DX_PIXEL_FORMAT_DXT3_UNORM: - case D3DX_PIXEL_FORMAT_DXT4_UNORM: - case D3DX_PIXEL_FORMAT_DXT5_UNORM: - assert(src_desc->format == D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); - break; + DWORD data_size; + void *data; + HRESULT hr;
- default: - FIXME("Unexpected compressed texture format %u.\n", dst_desc->format); - return E_NOTIMPL; - } + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_file %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), debugstr_w(src_file), + wine_dbgstr_rect(src_rect), filter, color_key, src_info);
- TRACE("Compressing pixels.\n"); - block_buf_row_pitch = src_desc->bytes_per_pixel * dst_desc->block_width; - for (z = 0; z < src_pixels->size.depth; ++z) - { - const uint8_t *src_slice = &((const uint8_t *)src_pixels->data)[z * src_pixels->slice_pitch]; - uint8_t *dst_slice = &((uint8_t *)dst_pixels->data)[z * dst_pixels->slice_pitch]; + if (!src_file || !dst_surface) + return D3DERR_INVALIDCALL;
- for (y = 0; y < src_pixels->size.height; y += dst_desc->block_height) - { - const unsigned int tmp_src_height = min(dst_desc->block_height, src_pixels->size.height - y); - uint8_t *dst_ptr = &dst_slice[(y / dst_desc->block_height) * dst_pixels->row_pitch]; - const uint8_t *src_ptr = &src_slice[y * src_pixels->row_pitch]; + if (FAILED(map_view_of_file(src_file, &data, &data_size))) + return D3DXERR_INVALIDDATA;
- for (x = 0; x < src_pixels->size.width; x += dst_desc->block_width) - { - const unsigned int tmp_src_width = min(dst_desc->block_width, src_pixels->size.width - x); - struct volume block_buf_size = { tmp_src_width, tmp_src_height, 1 }; - - if (tmp_src_width != dst_desc->block_width || tmp_src_height != dst_desc->block_height) - memset(block_buf, 0, sizeof(block_buf)); - copy_pixels(src_ptr, src_pixels->row_pitch, src_pixels->slice_pitch, block_buf, block_buf_row_pitch, 0, - &block_buf_size, src_desc); - d3dx_compress_block(dst_desc->format, block_buf, dst_ptr); - src_ptr += (src_desc->bytes_per_pixel * dst_desc->block_width); - dst_ptr += dst_desc->block_byte_count; - } - } - } + hr = D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, + data, data_size, src_rect, filter, color_key, src_info); + UnmapViewOfFile(data);
- return S_OK; + return hr; }
-HRESULT d3dx_pixels_init(const void *data, uint32_t row_pitch, uint32_t slice_pitch, - const PALETTEENTRY *palette, enum d3dx_pixel_format_id format, uint32_t left, uint32_t top, uint32_t right, - uint32_t bottom, uint32_t front, uint32_t back, struct d3dx_pixels *pixels) +HRESULT WINAPI D3DXLoadSurfaceFromResourceA(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const char *resource, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) { - const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(format); - const BYTE *ptr = data; - RECT unaligned_rect; - - memset(pixels, 0, sizeof(*pixels)); - if (is_unknown_format(fmt_desc)) - { - FIXME("Unsupported format %#x.\n", format); - return E_NOTIMPL; - } - - ptr += front * slice_pitch; - ptr += (top / fmt_desc->block_height) * row_pitch; - ptr += (left / fmt_desc->block_width) * fmt_desc->block_byte_count; + DWORD data_size; + HRSRC resinfo; + void *data;
- if (is_compressed_format(fmt_desc)) - { - uint32_t left_aligned, top_aligned; + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_a(resource), + wine_dbgstr_rect(src_rect), filter, color_key, src_info);
- top_aligned = top & ~(fmt_desc->block_height - 1); - left_aligned = left & ~(fmt_desc->block_width - 1); - SetRect(&unaligned_rect, left, top, right, bottom); - OffsetRect(&unaligned_rect, -left_aligned, -top_aligned); - } - else - { - SetRect(&unaligned_rect, 0, 0, (right - left), (bottom - top)); - } + if (!dst_surface) + return D3DERR_INVALIDCALL;
- if (!slice_pitch) - slice_pitch = row_pitch * (bottom - top); - set_d3dx_pixels(pixels, ptr, row_pitch, slice_pitch, palette, (right - left), (bottom - top), (back - front), - &unaligned_rect); + if (!(resinfo = FindResourceA(src_module, resource, (const char *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceA(src_module, resource, (const char *)RT_BITMAP))) + return D3DXERR_INVALIDDATA;
- return S_OK; -} + if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) + return D3DXERR_INVALIDDATA;
-static const char *debug_d3dx_pixels(struct d3dx_pixels *pixels) -{ - if (!pixels) - return "(null)"; - return wine_dbg_sprintf("(data %p, row_pitch %d, slice_pitch %d, palette %p, width %d, height %d, depth %d, " - "unaligned_rect %s)", pixels->data, pixels->row_pitch, pixels->slice_pitch, pixels->palette, - pixels->size.width, pixels->size.height, pixels->size.depth, wine_dbgstr_rect(&pixels->unaligned_rect)); + return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, + data, data_size, src_rect, filter, color_key, src_info); }
-HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, - const struct pixel_format_desc *dst_desc, struct d3dx_pixels *src_pixels, - const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) +HRESULT WINAPI D3DXLoadSurfaceFromResourceW(IDirect3DSurface9 *dst_surface, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, HMODULE src_module, const WCHAR *resource, + const RECT *src_rect, DWORD filter, D3DCOLOR color_key, D3DXIMAGE_INFO *src_info) { - struct volume src_size, dst_size, dst_size_aligned; - const struct d3dx_color_key *d3dx_ck = NULL; - struct d3dx_color_key d3dx_color_key; - HRESULT hr = S_OK; - - TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", - debug_d3dx_pixels(dst_pixels), dst_desc, debug_d3dx_pixels(src_pixels), src_desc, - filter_flags, color_key); - - if (is_compressed_format(src_desc)) - set_volume_struct(&src_size, (src_pixels->unaligned_rect.right - src_pixels->unaligned_rect.left), - (src_pixels->unaligned_rect.bottom - src_pixels->unaligned_rect.top), src_pixels->size.depth); - else - src_size = src_pixels->size; - - dst_size_aligned = dst_pixels->size; - if (is_compressed_format(dst_desc)) - set_volume_struct(&dst_size, (dst_pixels->unaligned_rect.right - dst_pixels->unaligned_rect.left), - (dst_pixels->unaligned_rect.bottom - dst_pixels->unaligned_rect.top), dst_pixels->size.depth); - else - dst_size = dst_size_aligned; - - /* Everything matches, simply copy the pixels. */ - if (src_desc->format == dst_desc->format - && (dst_size.width == src_size.width && !(dst_size.width % dst_desc->block_width)) - && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) - && (dst_size.depth == src_size.depth) - && color_key == 0 - && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) - && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) - && !(dst_pixels->unaligned_rect.left & (dst_desc->block_width - 1)) - && !(dst_pixels->unaligned_rect.top & (dst_desc->block_height - 1))) - { - TRACE("Simple copy.\n"); - copy_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, (void *)dst_pixels->data, - dst_pixels->row_pitch, dst_pixels->slice_pitch, &src_size, src_desc); - return S_OK; - } - - /* Stretching or format conversion. */ - if (!is_conversion_from_supported(src_desc) - || !is_conversion_to_supported(dst_desc)) - { - FIXME("Unsupported format conversion %#x -> %#x.\n", src_desc->format, dst_desc->format); - return E_NOTIMPL; - } - - if (is_index_format(src_desc) && (src_desc->block_width > 1)) - { - uint32_t unpacked_row_pitch, unpacked_slice_pitch; - const struct pixel_format_desc *unpacked_desc; - void *unpacked_mem = NULL; - - hr = d3dx_pixels_unpack_index(src_pixels, src_desc, &unpacked_mem, &unpacked_row_pitch, - &unpacked_slice_pitch, &unpacked_desc); - if (SUCCEEDED(hr)) - { - struct d3dx_pixels unpacked_pixels; - - d3dx_pixels_init(unpacked_mem, unpacked_row_pitch, unpacked_slice_pitch, src_pixels->palette, - unpacked_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, - 0, src_pixels->size.depth, &unpacked_pixels); - - hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &unpacked_pixels, unpacked_desc, - filter_flags, color_key); - } - free(unpacked_mem); - goto exit; - } - - /* - * If the source is a compressed image, we need to decompress it first - * before doing any modifications. - */ - if (is_compressed_format(src_desc)) - { - uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; - const struct pixel_format_desc *uncompressed_desc; - void *uncompressed_mem = NULL; - - hr = d3dx_pixels_decompress(src_pixels, src_desc, FALSE, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_slice_pitch, &uncompressed_desc); - if (SUCCEEDED(hr)) - { - struct d3dx_pixels uncompressed_pixels; - - d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, - uncompressed_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, - 0, src_pixels->size.depth, &uncompressed_pixels); - - if (sizeof(void *) == 4 && color_key) - { - TRACE("Clearing color key value on compressed source pixels.\n"); - color_key = 0; - } - hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, - filter_flags, color_key); - } - free(uncompressed_mem); - goto exit; - } - - /* Same as the above, need to decompress the destination prior to modifying. */ - if (is_compressed_format(dst_desc)) - { - uint32_t uncompressed_row_pitch, uncompressed_slice_pitch; - const struct pixel_format_desc *uncompressed_desc; - struct d3dx_pixels uncompressed_pixels; - void *uncompressed_mem = NULL; - - hr = d3dx_pixels_decompress(dst_pixels, dst_desc, TRUE, &uncompressed_mem, &uncompressed_row_pitch, - &uncompressed_slice_pitch, &uncompressed_desc); - if (FAILED(hr)) - goto exit; - - d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, - uncompressed_desc->format, dst_pixels->unaligned_rect.left, dst_pixels->unaligned_rect.top, - dst_pixels->unaligned_rect.right, dst_pixels->unaligned_rect.bottom, 0, dst_pixels->size.depth, - &uncompressed_pixels); - - hr = d3dx_load_pixels_from_pixels(&uncompressed_pixels, uncompressed_desc, src_pixels, src_desc, filter_flags, - color_key); - if (SUCCEEDED(hr)) - { - d3dx_pixels_init(uncompressed_mem, uncompressed_row_pitch, uncompressed_slice_pitch, NULL, - uncompressed_desc->format, 0, 0, dst_size_aligned.width, dst_size_aligned.height, 0, - dst_pixels->size.depth, &uncompressed_pixels); + DWORD data_size; + HRSRC resinfo; + void *data;
- hr = d3dx_pixels_compress(&uncompressed_pixels, uncompressed_desc, dst_pixels, dst_desc); - if (FAILED(hr)) - WARN("Failed to compress pixels, hr %#lx.\n", hr); - } - free(uncompressed_mem); - goto exit; - } + TRACE("dst_surface %p, dst_palette %p, dst_rect %s, src_module %p, resource %s, " + "src_rect %s, filter %#lx, color_key 0x%08lx, src_info %p.\n", + dst_surface, dst_palette, wine_dbgstr_rect(dst_rect), src_module, debugstr_w(resource), + wine_dbgstr_rect(src_rect), filter, color_key, src_info);
- if (color_key) - { - d3dx_init_color_key(src_desc, color_key, &d3dx_color_key); - d3dx_ck = &d3dx_color_key; - } + if (!dst_surface) + return D3DERR_INVALIDCALL;
- if ((filter_flags & 0xf) == D3DX_FILTER_NONE) - { - convert_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, - (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, dst_desc, - d3dx_ck, src_pixels->palette); - } - else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ - { - if ((filter_flags & 0xf) != D3DX_FILTER_POINT) - FIXME("Unhandled filter %#x.\n", filter_flags); - - /* Always apply a point filter until D3DX_FILTER_LINEAR, - * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ - point_filter_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, - src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, - dst_desc, d3dx_ck, src_pixels->palette); - } + if (!(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_RCDATA)) + /* Try loading the resource as bitmap data (which is in DIB format D3DXIFF_DIB) */ + && !(resinfo = FindResourceW(src_module, resource, (const WCHAR *)RT_BITMAP))) + return D3DXERR_INVALIDDATA;
-exit: - if (FAILED(hr)) - WARN("Failed to load pixels, hr %#lx.\n", hr); - return hr; -} + if (FAILED(load_resource_into_memory(src_module, resinfo, &data, &data_size))) + return D3DXERR_INVALIDDATA;
-void get_aligned_rect(uint32_t left, uint32_t top, uint32_t right, uint32_t bottom, uint32_t width, uint32_t height, - const struct pixel_format_desc *fmt_desc, RECT *aligned_rect) -{ - SetRect(aligned_rect, left, top, right, bottom); - if (aligned_rect->left & (fmt_desc->block_width - 1)) - aligned_rect->left = aligned_rect->left & ~(fmt_desc->block_width - 1); - if (aligned_rect->top & (fmt_desc->block_height - 1)) - aligned_rect->top = aligned_rect->top & ~(fmt_desc->block_height - 1); - if (aligned_rect->right & (fmt_desc->block_width - 1) && aligned_rect->right != width) - aligned_rect->right = min((aligned_rect->right + fmt_desc->block_width - 1) - & ~(fmt_desc->block_width - 1), width); - if (aligned_rect->bottom & (fmt_desc->block_height - 1) && aligned_rect->bottom != height) - aligned_rect->bottom = min((aligned_rect->bottom + fmt_desc->block_height - 1) - & ~(fmt_desc->block_height - 1), height); + return D3DXLoadSurfaceFromFileInMemory(dst_surface, dst_palette, dst_rect, + data, data_size, src_rect, filter, color_key, src_info); }
/************************************************************ diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c index 0313b209fce..55d69e78478 100644 --- a/dlls/d3dx9_36/util.c +++ b/dlls/d3dx9_36/util.c @@ -22,67 +22,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
-/************************************************************ - * pixel format table providing info about number of bytes per pixel, - * number of bits per channel and format type. - * - * Call get_format_info to request information about a specific format. - */ -static const struct pixel_format_desc formats[] = -{ - /* format bpc shifts bpp blocks alpha type rgb type flags */ - {D3DX_PIXEL_FORMAT_B8G8R8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 3, 1, 1, 3, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM, { 8, 8, 8, 8}, {24, 16, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM, { 0, 8, 8, 8}, { 0, 16, 8, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM, { 0, 8, 8, 8}, { 0, 0, 8, 16}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B5G6R5_UNORM, { 0, 5, 6, 5}, { 0, 11, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM, { 0, 5, 5, 5}, { 0, 10, 5, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM, { 1, 5, 5, 5}, {15, 10, 5, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B2G3R3_UNORM, { 0, 3, 3, 2}, { 0, 5, 2, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM, { 8, 3, 3, 2}, { 8, 5, 2, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM, { 4, 4, 4, 4}, {12, 8, 4, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM, { 0, 4, 4, 4}, { 0, 8, 4, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM, { 2, 10, 10, 10}, {30, 20, 10, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R16G16B16_UNORM, { 0, 16, 16, 16}, { 0, 0, 16, 32}, 6, 1, 1, 6, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_INTERNAL}, - {D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_UNORM, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_R16G16_UNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, 0 }, - {D3DX_PIXEL_FORMAT_A8_UNORM, { 8, 0, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_EMPTY, 0 }, - {D3DX_PIXEL_FORMAT_L8A8_UNORM, { 8, 8, 0, 0}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_L4A4_UNORM, { 4, 4, 0, 0}, { 4, 0, 0, 0}, 1, 1, 1, 1, CTYPE_UNORM, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_L8_UNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_L16_UNORM, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_LUMA, 0 }, - {D3DX_PIXEL_FORMAT_DXT1_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT2_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT3_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT5_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_R16_FLOAT, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R16G16_FLOAT, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R32_FLOAT, { 0, 32, 0, 0}, { 0, 0, 0, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R32G32_FLOAT, { 0, 32, 32, 0}, { 0, 0, 32, 0}, 8, 1, 1, 8, CTYPE_EMPTY, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT, {32, 32, 32, 32}, {96, 0, 32, 64}, 16, 1, 1, 16, CTYPE_FLOAT, CTYPE_FLOAT, 0 }, - {D3DX_PIXEL_FORMAT_P1_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 8, 1, 1, CTYPE_INDEX, CTYPE_INDEX, FMT_FLAG_INTERNAL}, - {D3DX_PIXEL_FORMAT_P2_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 4, 1, 1, CTYPE_INDEX, CTYPE_INDEX, FMT_FLAG_INTERNAL}, - {D3DX_PIXEL_FORMAT_P4_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 2, 1, 1, CTYPE_INDEX, CTYPE_INDEX, FMT_FLAG_INTERNAL}, - {D3DX_PIXEL_FORMAT_P8_UINT, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_INDEX, CTYPE_INDEX, 0 }, - {D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM, { 8, 8, 8, 8}, { 8, 0, 0, 0}, 2, 1, 1, 2, CTYPE_UNORM, CTYPE_INDEX, 0 }, - {D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, CTYPE_SNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM, {16, 16, 16, 16}, {48, 0, 16, 32}, 8, 1, 1, 8, CTYPE_SNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U8V8_SNORM, { 0, 8, 8, 0}, { 0, 0, 8, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U16V16_SNORM, { 0, 16, 16, 0}, { 0, 0, 16, 0}, 4, 1, 1, 4, CTYPE_EMPTY, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM, { 8, 8, 8, 0}, {16, 0, 8, 0}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM, { 2, 10, 10, 10}, {30, 0, 10, 20}, 4, 1, 1, 4, CTYPE_UNORM, CTYPE_SNORM, 0 }, - {D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - {D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - {D3DX_PIXEL_FORMAT_UYVY, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - {D3DX_PIXEL_FORMAT_YUY2, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 2, 1, 4, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_PACKED}, - /* marks last element */ - {D3DX_PIXEL_FORMAT_COUNT, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 0, 1, 1, 0, CTYPE_EMPTY, CTYPE_EMPTY, 0 }, -}; - D3DFORMAT d3dformat_from_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) { switch (format) @@ -310,11 +249,6 @@ HRESULT write_buffer_to_file(const WCHAR *dst_filename, ID3DXBuffer *buffer) return hr; }
-const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_format_id format) -{ - return &formats[min(format, D3DX_PIXEL_FORMAT_COUNT)]; -} - /************************************************************ * get_format_info * @@ -327,7 +261,7 @@ const struct pixel_format_desc *get_d3dx_pixel_format_info(enum d3dx_pixel_forma */ const struct pixel_format_desc *get_format_info(D3DFORMAT format) { - const struct pixel_format_desc *fmt_desc = &formats[d3dx_pixel_format_id_from_d3dformat(format)]; + const struct pixel_format_desc *fmt_desc = get_d3dx_pixel_format_info(d3dx_pixel_format_id_from_d3dformat(format));
if (is_unknown_format(fmt_desc)) FIXME("Unknown format %s.\n", debugstr_fourcc(format)); @@ -336,7 +270,7 @@ const struct pixel_format_desc *get_format_info(D3DFORMAT format)
const struct pixel_format_desc *get_format_info_idx(int idx) { - return idx < D3DX_PIXEL_FORMAT_COUNT ? &formats[idx] : NULL; + return idx < D3DX_PIXEL_FORMAT_COUNT ? get_d3dx_pixel_format_info(idx) : NULL; }
#define WINE_D3DX_TO_STR(x) case x: return #x diff --git a/dlls/d3dx9_37/Makefile.in b/dlls/d3dx9_37/Makefile.in index 6b7da8e56a3..0d6a6a2ea22 100644 --- a/dlls/d3dx9_37/Makefile.in +++ b/dlls/d3dx9_37/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=37 +EXTRADEFS = -DD3DX_SDK_VERSION=37 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_37.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_38/Makefile.in b/dlls/d3dx9_38/Makefile.in index 223b1165135..70fc0fb7d1d 100644 --- a/dlls/d3dx9_38/Makefile.in +++ b/dlls/d3dx9_38/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=38 +EXTRADEFS = -DD3DX_SDK_VERSION=38 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_38.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_39/Makefile.in b/dlls/d3dx9_39/Makefile.in index 63cfbba0672..649621272d5 100644 --- a/dlls/d3dx9_39/Makefile.in +++ b/dlls/d3dx9_39/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=39 +EXTRADEFS = -DD3DX_SDK_VERSION=39 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_39.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_40/Makefile.in b/dlls/d3dx9_40/Makefile.in index e76ef6de8a0..f8d1ed5147d 100644 --- a/dlls/d3dx9_40/Makefile.in +++ b/dlls/d3dx9_40/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=40 +EXTRADEFS = -DD3DX_SDK_VERSION=40 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_40.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_41/Makefile.in b/dlls/d3dx9_41/Makefile.in index 0951206c6eb..4dbbf216f2e 100644 --- a/dlls/d3dx9_41/Makefile.in +++ b/dlls/d3dx9_41/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=41 +EXTRADEFS = -DD3DX_SDK_VERSION=41 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_41.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 wined3d PARENTSRC = ../d3dx9_36 @@ -9,6 +9,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_42/Makefile.in b/dlls/d3dx9_42/Makefile.in index 697fa194d51..b3dd90f3e0b 100644 --- a/dlls/d3dx9_42/Makefile.in +++ b/dlls/d3dx9_42/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=42 +EXTRADEFS = -DD3DX_SDK_VERSION=42 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_42.dll IMPORTLIB = d3dx9_42 IMPORTS = d3d9 d3dcompiler_42 dxguid d3dxof ole32 gdi32 user32 @@ -10,6 +10,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \ diff --git a/dlls/d3dx9_43/Makefile.in b/dlls/d3dx9_43/Makefile.in index 7257b021dcb..725c276bf30 100644 --- a/dlls/d3dx9_43/Makefile.in +++ b/dlls/d3dx9_43/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DD3DX_SDK_VERSION=43 +EXTRADEFS = -DD3DX_SDK_VERSION=43 -DD3DX_D3D_VERSION=9 MODULE = d3dx9_43.dll IMPORTLIB = d3dx9_43 IMPORTS = d3d9 d3dcompiler_43 dxguid d3dxof ole32 gdi32 user32 @@ -10,6 +10,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ animation.c \ core.c \ + d3dx_helpers.c \ effect.c \ font.c \ line.c \
From: Connor McAdams cmcadams@codeweavers.com
This currently only supports non-DXT10 DDS files.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx10_43/Makefile.in | 5 +- dlls/d3dx10_43/dxhelpers.h | 2 + dlls/d3dx10_43/texture.c | 133 +++++++++++++++++++++++++++++++++++ dlls/d3dx9_36/d3dx_helpers.h | 35 +++++++++ 4 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx10_43/Makefile.in b/dlls/d3dx10_43/Makefile.in index 3d755499749..428f35e29bd 100644 --- a/dlls/d3dx10_43/Makefile.in +++ b/dlls/d3dx10_43/Makefile.in @@ -1,6 +1,8 @@ +EXTRADEFS = -DD3DX_D3D_VERSION=10 MODULE = d3dx10_43.dll IMPORTLIB = d3dx10 -IMPORTS = d3d10_1 d3dcompiler dxguid uuid gdi32 +IMPORTS = d3d10_1 d3dcompiler dxguid uuid gdi32 ole32 user32 +PARENTSRC = ../d3dx9_36 DELAYIMPORTS = windowscodecs
EXTRADLLFLAGS = -Wb,--prefer-native @@ -8,6 +10,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ async.c \ compiler.c \ + d3dx_helpers.c \ d3dx10_43_main.c \ font.c \ mesh.c \ diff --git a/dlls/d3dx10_43/dxhelpers.h b/dlls/d3dx10_43/dxhelpers.h index 50d509973cd..49f56d63a23 100644 --- a/dlls/d3dx10_43/dxhelpers.h +++ b/dlls/d3dx10_43/dxhelpers.h @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "../d3dx9_36/d3dx_helpers.h" + extern HRESULT load_file(const WCHAR *path, void **data, DWORD *size); extern HRESULT load_resourceA(HMODULE module, const char *resource, void **data, DWORD *size); diff --git a/dlls/d3dx10_43/texture.c b/dlls/d3dx10_43/texture.c index b925a07dd08..7d172264155 100644 --- a/dlls/d3dx10_43/texture.c +++ b/dlls/d3dx10_43/texture.c @@ -29,6 +29,76 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT sdk_version, IWICImagingFactory **imaging_factory);
+/* + * These are mappings from legacy DDS header formats to DXGI formats. Some + * don't map to a DXGI_FORMAT at all, and some only map to the default format. + */ +static DXGI_FORMAT dxgi_format_from_legacy_dds_d3dx_pixel_format_id(enum d3dx_pixel_format_id format) +{ + switch (format) + { + /* + * Some of these formats do have DXGI_FORMAT equivalents, but get + * mapped to DXGI_FORMAT_R8G8B8A8_UNORM instead. + */ + case D3DX_PIXEL_FORMAT_P8_UINT: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_P8_UINT_A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8B8X8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B8G8R8X8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B5G6R5_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B5G5R5X1_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B5G5R5A1_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B2G3R3_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B2G3R3A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B4G4R4A4_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_B4G4R4X4_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_L8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_L4A4_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case D3DX_PIXEL_FORMAT_L8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + + /* B10G10R10A2 doesn't exist in DXGI, both map to R10G10B10A2. */ + case D3DX_PIXEL_FORMAT_B10G10R10A2_UNORM: + case D3DX_PIXEL_FORMAT_R10G10B10A2_UNORM: return DXGI_FORMAT_R10G10B10A2_UNORM; + + case D3DX_PIXEL_FORMAT_U16V16W16Q16_SNORM: return DXGI_FORMAT_R16G16B16A16_SNORM; + case D3DX_PIXEL_FORMAT_L16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DX_PIXEL_FORMAT_R16G16B16A16_UNORM: return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DX_PIXEL_FORMAT_R16G16_UNORM: return DXGI_FORMAT_R16G16_UNORM; + case D3DX_PIXEL_FORMAT_A8_UNORM: return DXGI_FORMAT_A8_UNORM; + case D3DX_PIXEL_FORMAT_R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; + case D3DX_PIXEL_FORMAT_R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case D3DX_PIXEL_FORMAT_R32_FLOAT: return DXGI_FORMAT_R32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; + case D3DX_PIXEL_FORMAT_R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case D3DX_PIXEL_FORMAT_G8R8_G8B8_UNORM: return DXGI_FORMAT_G8R8_G8B8_UNORM; + case D3DX_PIXEL_FORMAT_R8G8_B8G8_UNORM: return DXGI_FORMAT_R8G8_B8G8_UNORM; + + case D3DX_PIXEL_FORMAT_DXT1_UNORM: return DXGI_FORMAT_BC1_UNORM; + case D3DX_PIXEL_FORMAT_DXT2_UNORM: return DXGI_FORMAT_BC2_UNORM; + case D3DX_PIXEL_FORMAT_DXT3_UNORM: return DXGI_FORMAT_BC2_UNORM; + case D3DX_PIXEL_FORMAT_DXT4_UNORM: return DXGI_FORMAT_BC3_UNORM; + case D3DX_PIXEL_FORMAT_DXT5_UNORM: return DXGI_FORMAT_BC3_UNORM; + + /* These formats are known and explicitly unsupported on d3dx10+. */ + case D3DX_PIXEL_FORMAT_U8V8W8Q8_SNORM: + case D3DX_PIXEL_FORMAT_U8V8_SNORM: + case D3DX_PIXEL_FORMAT_U16V16_SNORM: + case D3DX_PIXEL_FORMAT_U8V8_SNORM_L8X8_UNORM: + case D3DX_PIXEL_FORMAT_U10V10W10_SNORM_A2_UNORM: + case D3DX_PIXEL_FORMAT_UYVY: + case D3DX_PIXEL_FORMAT_YUY2: + return DXGI_FORMAT_UNKNOWN; + + default: + FIXME("Unknown d3dx_pixel_format_id %#x.\n", format); + return DXGI_FORMAT_UNKNOWN; + } +} + static const struct { const GUID *wic_container_guid; @@ -423,6 +493,55 @@ HRESULT WINAPI D3DX10GetImageInfoFromResourceW(HMODULE module, const WCHAR *reso return hr; }
+static HRESULT d3dx10_image_info_from_d3dx_image(D3DX10_IMAGE_INFO *info, struct d3dx_image *image) +{ + DXGI_FORMAT format = dxgi_format_from_legacy_dds_d3dx_pixel_format_id(image->format); + HRESULT hr = S_OK; + + memset(info, 0, sizeof(*info)); + if (format == DXGI_FORMAT_UNKNOWN) + { + WARN("Tried to load DDS file with unsupported format %#x.\n", image->format); + return E_FAIL; + } + + info->ImageFileFormat = (D3DX10_IMAGE_FILE_FORMAT)image->image_file_format; + if (info->ImageFileFormat == D3DX10_IFF_FORCE_DWORD) + { + ERR("Unsupported d3dx image file.\n"); + return E_FAIL; + } + + info->Width = image->size.width; + info->Height = image->size.height; + info->Depth = image->size.depth; + info->ArraySize = image->layer_count; + info->MipLevels = image->mip_levels; + info->Format = format; + switch (image->resource_type) + { + case D3DX_RESOURCE_TYPE_TEXTURE_2D: + info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + break; + + case D3DX_RESOURCE_TYPE_CUBE_TEXTURE: + info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; + info->MiscFlags |= D3D10_RESOURCE_MISC_TEXTURECUBE; + break; + + case D3DX_RESOURCE_TYPE_TEXTURE_3D: + info->ResourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE3D; + break; + + default: + ERR("Unhandled resource type %d.\n", image->resource_type); + hr = E_FAIL; + break; + } + + return hr; +} + HRESULT get_image_info(const void *data, SIZE_T size, D3DX10_IMAGE_INFO *img_info) { IWICBitmapFrameDecode *frame = NULL; @@ -432,9 +551,23 @@ HRESULT get_image_info(const void *data, SIZE_T size, D3DX10_IMAGE_INFO *img_inf WICDdsParameters dds_params; IWICStream *stream = NULL; unsigned int frame_count; + struct d3dx_image image; GUID container_format; HRESULT hr;
+ if (!data || !size) + return E_FAIL; + + if (SUCCEEDED(d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_INFO_ONLY)) + && image.image_file_format == D3DX_IMAGE_FILE_FORMAT_DDS) + { + if (SUCCEEDED(d3dx10_image_info_from_d3dx_image(img_info, &image))) + { + TRACE("Successfully retrieved image info from shared code.\n"); + return S_OK; + } + } + WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); IWICImagingFactory_CreateStream(factory, &stream); hr = IWICStream_InitializeFromMemory(stream, (BYTE *)data, size); diff --git a/dlls/d3dx9_36/d3dx_helpers.h b/dlls/d3dx9_36/d3dx_helpers.h index fb139ed8cb9..7bfd7e88be3 100644 --- a/dlls/d3dx9_36/d3dx_helpers.h +++ b/dlls/d3dx9_36/d3dx_helpers.h @@ -29,6 +29,41 @@ #include "d3dx9.h" #endif /* D3DX_D3D_VERSION == 9 */
+#if D3DX_D3D_VERSION == 10 +#define COBJMACROS +#include "d3dx10.h" + +#define D3DERR_INVALIDCALL 0x8876086c +#define D3DXERR_INVALIDDATA D3DX10_ERR_INVALID_DATA +#define D3D_OK S_OK + +#define D3DX_FILTER_NONE D3DX10_FILTER_NONE +#define D3DX_FILTER_POINT D3DX10_FILTER_POINT +#define D3DX_FILTER_LINEAR D3DX10_FILTER_LINEAR +#define D3DX_FILTER_TRIANGLE D3DX10_FILTER_TRIANGLE +#define D3DX_FILTER_BOX D3DX10_FILTER_BOX +#define D3DX_FILTER_MIRROR_U D3DX10_FILTER_MIRROR_U +#define D3DX_FILTER_MIRROR_V D3DX10_FILTER_MIRROR_V +#define D3DX_FILTER_MIRROR_W D3DX10_FILTER_MIRROR_W +#define D3DX_FILTER_MIRROR D3DX10_FILTER_MIRROR +#define D3DX_FILTER_DITHER D3DX10_FILTER_DITHER +#define D3DX_FILTER_DITHER_DIFFUSION D3DX10_FILTER_DITHER_DIFFUSION +#define D3DX_FILTER_SRGB_IN D3DX10_FILTER_SRGB_IN +#define D3DX_FILTER_SRGB_OUT D3DX10_FILTER_SRGB_OUT +#define D3DX_FILTER_SRGB D3DX10_FILTER_SRGB + +#define ID3DXBuffer ID3D10Blob +#define D3DXCreateBuffer(size, blob) D3D10CreateBlob(size, blob) +#define ID3DXBuffer_GetBufferPointer(blob) ID3D10Blob_GetBufferPointer(blob) +#define ID3DXBuffer_Release(blob) ID3D10Blob_Release(blob) + +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) +#endif +#endif /* D3DX_D3D_VERSION == 10 */ + #define DDS_PALETTE_SIZE (sizeof(PALETTEENTRY) * 256)
/* dds_header.flags */
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image) {
- info->ImageFileFormat = image->image_file_format;
- info->ImageFileFormat = (D3DXIMAGE_FILEFORMAT)image->image_file_format;
I haven't really checked how this looks in the end, so this might be a bad take on my part, but this cast kinda rings a bell. Here I'd expect a call to a (likely trivial) function converting from the d3dx-neutral `enum d3dx_image_file_format` to the d3dx9-specific `D3DXIMAGE_FILEFORMAT`. The function could also validate the values if need be (or make it simple to add that later on if not necessary right away).
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
return hr; }
- hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, file_format, &buffer);
- hr = d3dx_save_pixels_to_memory(&src_pixels, src_fmt_desc, (enum d3dx_image_file_format)file_format, &buffer);
Same here but in reverse.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/d3dx_helpers.c:
+#include "wine/debug.h" +#include "d3dx_helpers.h"
+#include "initguid.h" +#include "ole2.h" +#include "wincodec.h"
+#define BCDEC_IMPLEMENTATION +#define BCDEC_STATIC +#include "bcdec.h" +#define STB_DXT_IMPLEMENTATION +#define STB_DXT_STATIC +#include "stb_dxt.h" +#include <assert.h>
Extra blank.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/d3dx_helpers.c:
src_bytes_left -= rle_packet_size;
pixel_count += rle_count;
if (!src_bytes_left && pixel_count != row_width)
return D3DXERR_INVALIDDATA;
- }
- *src = src_ptr;
- return D3D_OK;
+}
+struct d3dx_color_key; +static 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,
const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key,
const PALETTEENTRY *palette);
+static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size,
We could probably add a blank line above the `d3dx_image_tga_decode()` definition while at it.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/d3dx_helpers.h:
#include "d3dx9.h" #endif /* D3DX_D3D_VERSION == 9 */
+#if D3DX_D3D_VERSION == 10 +#define COBJMACROS +#include "d3dx10.h"
I'm a bit torn on this...
It would be nice if we could avoid including d3dx* headers from here. That way we're sure that we're not depending on anything version-specific in the generic code. It shouldn't usually make things more complicated, e.g. the `D3DX_FILTER_` defines could just be copied from the d3dx9 header and used unchanged instead of defining them to the `D3DX10_` (or `D3DX11_`) version.
The one annoying bit with this is the `ID3DXBuffer` / `ID3D10Blob` / `ID3DBlob` mess. I haven't thought this through but it might make the whole thing not worth it. Maybe you already tried something like this and discarded it; let me know.
Either way, I'd move the `#define COBJMACROS` out of the .h and into the .c files using it, otherwise it affects all the following includes which might come as a bit of a surprise.
Patch 4 is a bit big, but it's just copying code from various source files into a single source file. I can attempt to split if if that's preferable for review purposes.
It's fine, `git show --color-moved` helped quite a bit :slight_smile:
On Tue Jul 8 22:53:13 2025 +0000, Matteo Bruni wrote:
I'm a bit torn on this... It would be nice if we could avoid including d3dx* headers from here. That way we're sure that we're not depending on anything version-specific in the generic code. It shouldn't usually make things more complicated, e.g. the `D3DX_FILTER_` defines could just be copied from the d3dx9 header and used unchanged instead of defining them to the `D3DX10_` (or `D3DX11_`) version. The one annoying bit with this is the `ID3DXBuffer` / `ID3D10Blob` / `ID3DBlob` mess. I haven't thought this through but it might make the whole thing not worth it. Maybe you already tried something like this and discarded it; let me know. Either way, I'd move the `#define COBJMACROS` out of the .h and into the .c files using it, otherwise it affects all the following includes which might come as a bit of a surprise.
The `ID3DXBuffer`/ `ID3D10Blob` / `ID3DBlob` was what ultimately led me to doing that. Originally I was just returning allocated memory/size from the saving to file function, creating the appropriate buffer interface, and copying it over. That feels a bit wasteful WRT memory.
In theory we're the ones implementing those interfaces in the first place, so we could add some way to do the equivalent of `D3DXCreateBuffer()` / `D3D10CreateBlob()` / `D3DCreateBlob()` with preallocated memory.
The other alternative is to do a kind of dry run to get the size first, then pass in the allocated memory on the second call. That ends up with extra code complexity that felt a bit messy to me at the time.
On Wed Jul 9 13:54:19 2025 +0000, Connor McAdams wrote:
The `ID3DXBuffer`/ `ID3D10Blob` / `ID3DBlob` was what ultimately led me to doing that. Originally I was just returning allocated memory/size from the saving to file function, creating the appropriate buffer interface, and copying it over. That feels a bit wasteful WRT memory. In theory we're the ones implementing those interfaces in the first place, so we could add some way to do the equivalent of `D3DXCreateBuffer()` / `D3D10CreateBlob()` / `D3DCreateBlob()` with preallocated memory. The other alternative is to do a kind of dry run to get the size first, then pass in the allocated memory on the second call. That ends up with extra code complexity that felt a bit messy to me at the time.
Maybe we could introduce a thin wrapper around `D3DXCreateBuffer()` and the buffer / blob methods we use, implemented by each of the d3dx* and passed to `d3dx_save_pixels_to_memory()`.
It feels like it should be a good fit for this case but, as usual, it will be clear only after trying...
On Tue Jul 8 22:53:12 2025 +0000, Matteo Bruni wrote:
I haven't really checked how this looks in the end, so this might be a bad take on my part, but this cast kinda rings a bell. Here I'd expect a call to a (likely trivial) function converting from the d3dx-neutral `enum d3dx_image_file_format` to the d3dx9-specific `D3DXIMAGE_FILEFORMAT`. The function could also validate the values if need be (or make it simple to add that later on if not necessary right away).
Working on this a bit alongside the `ID3DXBuffer` issue has lead me to another question, how API agnostic do we want this helper source file to be?
Just as an example, each d3dx API has it's own `D3DXERR_INVALIDDATA`/`D3DX10_ERR_INVALID_DATA`/`D3DX11_ERR_INVALID_DATA`. Would you prefer to have our own `D3DX_ERROR_INVALID_DATA` error code that gets translated to the proper return code in each module with a `d3dx10_error_from_d3dx_error()` type of helper? Or should we go with the: ``` #if D3DX_D3D_VERSION == 10 #define D3DXERR_INVALIDDATA D3DX10_ERR_INVALID_DATA #endif ``` way of handling it?
This also relates a bit to the `D3DXIMAGE_FILEFORMAT` translation I'm doing here, in my later patches I have the image file formats unsupported by d3dx9 gated behind an API check, e.g you don't need a conversion function because calling into d3dx_helpers from d3dx9 would never successfully return a `D3DX10_IFF_GIF` for example. If the plan is to eventually use this outside of just our d3dx modules, which I think was mentioned in a discussion awhile ago, I think the agnostic approach makes more sense. I just wasn't sure if that's still something we were interested in. :)
On Thu Jul 10 15:36:26 2025 +0000, Connor McAdams wrote:
Working on this a bit alongside the `ID3DXBuffer` issue has lead me to another question, how API agnostic do we want this helper source file to be? Just as an example, each d3dx API has it's own `D3DXERR_INVALIDDATA`/`D3DX10_ERR_INVALID_DATA`/`D3DX11_ERR_INVALID_DATA`. Would you prefer to have our own `D3DX_ERROR_INVALID_DATA` error code that gets translated to the proper return code in each module with a `d3dx10_error_from_d3dx_error()` type of helper? Or should we go with the:
#if D3DX_D3D_VERSION == 10 #define D3DXERR_INVALIDDATA D3DX10_ERR_INVALID_DATA #endif
way of handling it? This also relates a bit to the `D3DXIMAGE_FILEFORMAT` translation I'm doing here, in my later patches I have the image file formats unsupported by d3dx9 gated behind an API check, e.g you don't need a conversion function because calling into d3dx_helpers from d3dx9 would never successfully return a `D3DX10_IFF_GIF` for example. If the plan is to eventually use this outside of just our d3dx modules, which I think was mentioned in a discussion awhile ago, I think the agnostic approach makes more sense. I just wasn't sure if that's still something we were interested in. :)
Actually, it looks like the actual values of the `D3DXERR` HRESULTs are the same across each API, the difference I was thinking of was `D3DERR_NOTFOUND`/`D3D10_ERROR_FILE_NOT_FOUND`/`D3D11_ERROR_FILE_NOT_FOUND`. Those do have different values across each API and would likely require a helper function or `#ifdef`s to avoid that.
The `D3DXERR` values are shared across all d3dx versions, as are the filter flag values. So, IMO those wouldn't benefit as much from a helper function here.
This also relates a bit to the `D3DXIMAGE_FILEFORMAT` translation I'm doing here, in my later patches I have the image file formats unsupported by d3dx9 gated behind an API check, e.g you don't need a conversion function because calling into d3dx_helpers from d3dx9 would never successfully return a `D3DX10_IFF_GIF` for example.
Right, I was imagining something like this, which is why I put it like "a conversion function allows validation, even if we don't actually need it". For this hunk specifically I think a trivial conversion function with no checks would still look nicer than a cast.
In general I think what you're doing is fine. We can always add abstraction afterwards as needed if we're going to add more users or move the whole thing out of Wine. Not including d3dx*.h from d3dx_helpers.h would be helpful even besides those additional use cases, but it's probably not worth it if it makes things too convoluted **now**.
On Thu Jul 10 20:37:06 2025 +0000, Matteo Bruni wrote:
This also relates a bit to the `D3DXIMAGE_FILEFORMAT` translation I'm
doing here, in my later patches I have the image file formats unsupported by d3dx9 gated behind an API check, e.g you don't need a conversion function because calling into d3dx_helpers from d3dx9 would never successfully return a `D3DX10_IFF_GIF` for example. Right, I was imagining something like this, which is why I put it like "a conversion function allows validation, even if we don't actually need it". For this hunk specifically I think a trivial conversion function with no checks would still look nicer than a cast. In general I think what you're doing is fine. We can always add abstraction afterwards as needed if we're going to add more users or move the whole thing out of Wine. Not including d3dx*.h from d3dx_helpers.h would be helpful even besides those additional use cases, but it's probably not worth it if it makes things too convoluted **now**.
Just clarifying that the helper function can simply be a glorified / hidden away cast. But since we're introducing our own `enum d3dx_image_file_format` anyway it seems proper to have conversion functions as well, even if they're effectively NOPs.