From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 90 +++++++++++++++++++++++++++++++++++ dlls/d3dx9_36/tests/surface.c | 28 +++++------ 2 files changed, 101 insertions(+), 17 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index eca87f75322..0fa918bbf2e 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -989,6 +989,93 @@ exit: return hr; }
+static D3DFORMAT d3dx_get_tga_format_for_bpp(uint8_t bpp) +{ + switch (bpp) + { + case 15: return D3DFMT_X1R5G5B5; + case 16: return D3DFMT_A1R5G5B5; + case 24: return D3DFMT_R8G8B8; + case 32: return D3DFMT_A8R8G8B8; + default: + WARN("Unhandled bpp %u for targa.\n", bpp); + return D3DFMT_UNKNOWN; + } +} + +#define IMAGETYPE_COLORMAPPED 1 +#define IMAGETYPE_TRUECOLOR 2 +#define IMAGETYPE_GRAYSCALE 3 +#define IMAGETYPE_MASK 0x07 +#define IMAGETYPE_RLE 8 + +#include "pshpack1.h" +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; +}; +#include "poppack.h" + +static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image) +{ + const struct tga_header *header = (src_data_size >= sizeof(*header)) ? (const struct tga_header *)src_data : NULL; + uint32_t expected_header_size = sizeof(*header); + + if (!header) + return D3DXERR_INVALIDDATA; + + expected_header_size += header->id_length; + expected_header_size += header->color_map_length * ((header->color_map_entrysize + 7) >> 3); + 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) == D3DFMT_UNKNOWN))) + return D3DXERR_INVALIDDATA; + + switch (header->image_type & IMAGETYPE_MASK) + { + case IMAGETYPE_COLORMAPPED: + if (header->depth != 8 || !header->color_map_type) + return D3DXERR_INVALIDDATA; + image->format = D3DFMT_P8; + break; + + case IMAGETYPE_TRUECOLOR: + if (d3dx_get_tga_format_for_bpp(header->depth) == D3DFMT_UNKNOWN) + return D3DXERR_INVALIDDATA; + image->format = d3dx_get_tga_format_for_bpp(header->depth); + break; + + case IMAGETYPE_GRAYSCALE: + if (header->depth != 8) + return D3DXERR_INVALIDDATA; + image->format = D3DFMT_L8; + 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 = D3DRTYPE_TEXTURE; + image->image_file_format = D3DXIFF_TGA; + + 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) { @@ -1014,6 +1101,9 @@ HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3d }
/* Last resort, try TGA. */ + if (flags & D3DX_IMAGE_INFO_ONLY) + return d3dx_initialize_image_from_tga(src_data, src_data_size, image); + return d3dx_initialize_image_from_wic(src_data, src_data_size, image, D3DXIFF_TGA, flags); }
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 17ac86cb38e..7092c8972b8 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -630,11 +630,11 @@ static void test_tga_header_handling(void) } info_tests[] = { /* 15 bpp true color. */ { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, - { D3D_OK, 4, 4, D3DFMT_X1R5G5B5 }, .todo_hr = TRUE + { D3D_OK, 4, 4, D3DFMT_X1R5G5B5 } }, /* 16 bpp true color. */ { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, - { D3D_OK, 4, 4, D3DFMT_A1R5G5B5 }, .todo_info = TRUE + { D3D_OK, 4, 4, D3DFMT_A1R5G5B5 } }, /* 24 bpp true color. */ { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 24, 0 }, @@ -642,7 +642,7 @@ static void test_tga_header_handling(void) }, /* 32 bpp true color. */ { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 32, 0 }, - { D3D_OK, 4, 4, D3DFMT_A8R8G8B8 }, .todo_info = TRUE + { D3D_OK, 4, 4, D3DFMT_A8R8G8B8 } }, /* 8 bit paletted, 15 bpp palette. */ { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 15, 0, 0, 4, 4, 8, 0 }, @@ -708,8 +708,7 @@ static void test_tga_header_handling(void) /* Image descriptor field is ignored. */ tga->header.image_descriptor = 0xcf; check_tga_image_info(tga, file_size, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, SUCCEEDED(info_tests[i].expected.hr), - info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info);
if (FAILED(info_tests[i].expected.hr)) goto next; @@ -722,12 +721,12 @@ static void test_tga_header_handling(void) tmp_footer.extension_area_offset = 65536; memcpy(&tga->data[info_tests[i].extra_header_size], &tmp_footer, sizeof(tmp_footer)); check_tga_image_info(tga, file_size + sizeof(tmp_footer), info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, TRUE, info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info);
/* Check RLE type. */ tga->header.image_type |= IMAGETYPE_RLE; check_tga_image_info(tga, file_size, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, TRUE, info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info); tga->header.image_type &= ~IMAGETYPE_RLE;
if (tga->header.image_type == IMAGETYPE_COLORMAPPED) @@ -739,16 +738,14 @@ static void test_tga_header_handling(void) */ tga->header.color_map_length = 1; check_tga_image_info(tga, file_size, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, SUCCEEDED(info_tests[i].expected.hr), - info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info);
tga->header.color_map_entrysize = 8; check_tga_image_info(tga, file_size, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA, FALSE, FALSE);
/* Add a byte to file size to account for color map. */ check_tga_image_info(tga, file_size + 1, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, SUCCEEDED(info_tests[i].expected.hr), - info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info);
/* ID length field is also considered. */ tga->header.id_length = 1; @@ -756,8 +753,7 @@ static void test_tga_header_handling(void)
/* Add another byte to file size to account for id length. */ check_tga_image_info(tga, file_size + 2, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, SUCCEEDED(info_tests[i].expected.hr), - info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info);
/* * If the color map type field is set but the color map fields @@ -777,14 +773,12 @@ static void test_tga_header_handling(void) /* 16 is a valid entry size. */ tga->header.color_map_entrysize = 16; check_tga_image_info(tga, file_size + 2, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, SUCCEEDED(info_tests[i].expected.hr), - info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info);
/* First entry doesn't factor into validation. */ tga->header.color_map_firstentry = 512; check_tga_image_info(tga, file_size + 2, info_tests[i].expected.width, info_tests[i].expected.height, - info_tests[i].expected.format, info_tests[i].expected.hr, SUCCEEDED(info_tests[i].expected.hr), - info_tests[i].todo_info); + info_tests[i].expected.format, info_tests[i].expected.hr, info_tests[i].todo_hr, info_tests[i].todo_info); next: winetest_pop_context(); }