These patches finish moving targa file handling into d3dx9.
-- v2: d3dx9: Add support for decoding targa files with a color map in d3dx9. d3dx9: Add support for decoding targa files with run length encoding in d3dx9. d3dx9: Add support for decoding targa files with different pixel orders in d3dx9. d3dx9: Add support for loading basic targa images without WIC. d3dx9/tests: Add more tests for loading targa files.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 8555464fefb..e7cc884bc59 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -596,20 +596,20 @@ static const struct tga_footer default_tga_footer = { { 'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', 0 } };
-#define check_tga_image_info(tga, tga_size, expected_width, expected_height, expected_format, expected_hr, todo_hr, todo_info) \ - check_tga_image_info_(__LINE__, tga, tga_size, expected_width, expected_height, expected_format, expected_hr, todo_hr, todo_info) +#define check_tga_image_info(tga, tga_size, expected_width, expected_height, expected_format, expected_hr) \ + check_tga_image_info_(__LINE__, tga, tga_size, expected_width, expected_height, expected_format, expected_hr) static void check_tga_image_info_(uint32_t line, const void *tga, uint32_t tga_size, uint32_t expected_width, - uint32_t expected_height, D3DFORMAT expected_format, HRESULT expected_hr, BOOL todo_hr, BOOL todo_info) + uint32_t expected_height, D3DFORMAT expected_format, HRESULT expected_hr) { D3DXIMAGE_INFO info = { 0 }; HRESULT hr;
hr = D3DXGetImageInfoFromFileInMemory(tga, tga_size, &info); - todo_wine_if(todo_hr) ok_(__FILE__, line)(hr == expected_hr, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(hr == expected_hr, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(expected_hr) && SUCCEEDED(hr)) { check_image_info_(__FILE__, line, &info, expected_width, expected_height, 1, 1, expected_format, - D3DRTYPE_TEXTURE, D3DXIFF_TGA, todo_info); + D3DRTYPE_TEXTURE, D3DXIFF_TGA, FALSE); } }
@@ -693,18 +693,18 @@ static void test_tga_header_handling(void)
tga->header = info_tests[i].header; 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
/* X/Y origin fields are ignored. */ tga->header.xorigin = tga->header.width + 1; tga->header.yorigin = tga->header.height + 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
/* 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
if (FAILED(info_tests[i].expected.hr)) goto next; @@ -717,12 +717,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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
/* 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr); tga->header.image_type &= ~IMAGETYPE_RLE;
if (tga->header.image_type == IMAGETYPE_COLORMAPPED) @@ -734,22 +734,22 @@ 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
tga->header.color_map_entrysize = 8; - check_tga_image_info(tga, file_size, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA, FALSE, FALSE); + check_tga_image_info(tga, file_size, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA);
/* 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
/* ID length field is also considered. */ tga->header.id_length = 1; - check_tga_image_info(tga, file_size + 1, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA, FALSE, FALSE); + check_tga_image_info(tga, file_size + 1, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA);
/* 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
/* * If the color map type field is set but the color map fields @@ -759,22 +759,22 @@ static void test_tga_header_handling(void) */ tga->header.id_length = tga->header.color_map_entrysize = tga->header.color_map_length = 0; tga->header.color_map_type = COLORMAP_TYPE_ONE; - check_tga_image_info(tga, file_size + 2, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA, FALSE, FALSE); + check_tga_image_info(tga, file_size + 2, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA);
/* 8 isn't a valid entry size. */ tga->header.color_map_entrysize = 8; tga->header.color_map_length = 1; - check_tga_image_info(tga, file_size + 1, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA, FALSE, FALSE); + check_tga_image_info(tga, file_size + 1, 0, 0, D3DFMT_UNKNOWN, D3DXERR_INVALIDDATA);
/* 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr);
/* 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, FALSE, FALSE); + info_tests[i].expected.format, info_tests[i].expected.hr); next: winetest_pop_context(); }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 626 ++++++++++++++++++++++++++++++++++ 1 file changed, 626 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index e7cc884bc59..6653dc91611 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -566,6 +566,9 @@ static void test_dds_header_handling(void) #define IMAGETYPE_GRAYSCALE 3 #define IMAGETYPE_RLE 8
+#define IMAGE_RIGHTTOLEFT 0x10 +#define IMAGE_TOPTOBOTTOM 0x20 + #include "pshpack1.h" struct tga_header { @@ -1276,15 +1279,22 @@ static uint32_t get_bpp_for_d3dformat(D3DFORMAT format) case D3DFMT_Q16W16V16U16: return 8;
+ case D3DFMT_A8B8G8R8: case D3DFMT_A8R8G8B8: case D3DFMT_V16U16: case D3DFMT_G16R16: return 4;
+ case D3DFMT_R8G8B8: + return 3; + + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: case D3DFMT_V8U8: case D3DFMT_A8P8: return 2;
+ case D3DFMT_L8: case D3DFMT_P8: return 1;
@@ -1525,6 +1535,621 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) IDirect3DSurface9_Release(decomp_surf); }
+static const uint8_t test_tga_color_map_15bpp[] = +{ + 0x00,0x00,0x10,0x00,0x00,0x02,0x10,0x02,0x00,0x40,0x10,0x40,0x00,0x42,0x18,0x63, + 0x78,0x63,0x34,0x7b,0x88,0x00,0x8c,0x00,0x90,0x00,0x94,0x00,0x98,0x00,0x9c,0x00, + 0x00,0x01,0x04,0x01,0x08,0x01,0x0c,0x01,0x10,0x01,0x14,0x01,0x18,0x01,0x1c,0x01, + 0x80,0x01,0x84,0x01,0x88,0x01,0x8c,0x01,0x90,0x01,0x94,0x01,0x98,0x01,0x9c,0x01, + 0x00,0x02,0x04,0x02,0x08,0x02,0x0c,0x02,0x10,0x02,0x14,0x02,0x18,0x02,0x1c,0x02, + 0x80,0x02,0x84,0x02,0x88,0x02,0x8c,0x02,0x90,0x02,0x94,0x02,0x98,0x02,0x9c,0x02, + 0x00,0x03,0x04,0x03,0x08,0x03,0x0c,0x03,0x10,0x03,0x14,0x03,0x18,0x03,0x1c,0x03, + 0x80,0x03,0x84,0x03,0x88,0x03,0x8c,0x03,0x90,0x03,0x94,0x03,0x98,0x03,0x9c,0x03, + 0x00,0x20,0x04,0x20,0x08,0x20,0x0c,0x20,0x10,0x20,0x14,0x20,0x18,0x20,0x1c,0x20, + 0x80,0x20,0x84,0x20,0x88,0x20,0x8c,0x20,0x90,0x20,0x94,0x20,0x98,0x20,0x9c,0x20, + 0x00,0x21,0x04,0x21,0x08,0x21,0x0c,0x21,0x10,0x21,0x14,0x21,0x18,0x21,0x1c,0x21, + 0x80,0x21,0x84,0x21,0x88,0x21,0x8c,0x21,0x90,0x21,0x94,0x21,0x98,0x21,0x9c,0x21, + 0x00,0x22,0x04,0x22,0x08,0x22,0x0c,0x22,0x10,0x22,0x14,0x22,0x18,0x22,0x1c,0x22, + 0x80,0x22,0x84,0x22,0x88,0x22,0x8c,0x22,0x90,0x22,0x94,0x22,0x98,0x22,0x9c,0x22, + 0x00,0x23,0x04,0x23,0x08,0x23,0x0c,0x23,0x10,0x23,0x14,0x23,0x18,0x23,0x1c,0x23, + 0x80,0x23,0x84,0x23,0x88,0x23,0x8c,0x23,0x90,0x23,0x94,0x23,0x98,0x23,0x9c,0x23, + 0x00,0x40,0x04,0x40,0x08,0x40,0x0c,0x40,0x10,0x40,0x14,0x40,0x18,0x40,0x1c,0x40, + 0x80,0x40,0x84,0x40,0x88,0x40,0x8c,0x40,0x90,0x40,0x94,0x40,0x98,0x40,0x9c,0x40, + 0x00,0x41,0x04,0x41,0x08,0x41,0x0c,0x41,0x10,0x41,0x14,0x41,0x18,0x41,0x1c,0x41, + 0x80,0x41,0x84,0x41,0x88,0x41,0x8c,0x41,0x90,0x41,0x94,0x41,0x98,0x41,0x9c,0x41, + 0x00,0x42,0x04,0x42,0x08,0x42,0x0c,0x42,0x10,0x42,0x14,0x42,0x18,0x42,0x1c,0x42, + 0x80,0x42,0x84,0x42,0x88,0x42,0x8c,0x42,0x90,0x42,0x94,0x42,0x98,0x42,0x9c,0x42, + 0x00,0x43,0x04,0x43,0x08,0x43,0x0c,0x43,0x10,0x43,0x14,0x43,0x18,0x43,0x1c,0x43, + 0x80,0x43,0x84,0x43,0x88,0x43,0x8c,0x43,0x90,0x43,0x94,0x43,0x98,0x43,0x9c,0x43, + 0x00,0x60,0x04,0x60,0x08,0x60,0x0c,0x60,0x10,0x60,0x14,0x60,0x18,0x60,0x1c,0x60, + 0x80,0x60,0x84,0x60,0x88,0x60,0x8c,0x60,0x90,0x60,0x94,0x60,0x98,0x60,0x9c,0x60, + 0x00,0x61,0x04,0x61,0x08,0x61,0x0c,0x61,0x10,0x61,0x14,0x61,0x18,0x61,0x1c,0x61, + 0x80,0x61,0x84,0x61,0x88,0x61,0x8c,0x61,0x90,0x61,0x94,0x61,0x98,0x61,0x9c,0x61, + 0x00,0x62,0x04,0x62,0x08,0x62,0x0c,0x62,0x10,0x62,0x14,0x62,0x18,0x62,0x1c,0x62, + 0x80,0x62,0x84,0x62,0x88,0x62,0x8c,0x62,0x90,0x62,0x94,0x62,0x98,0x62,0x9c,0x62, + 0x00,0x63,0x04,0x63,0x08,0x63,0x0c,0x63,0x10,0x63,0x14,0x63,0xff,0x7b,0x94,0x52, + 0x10,0x42,0x1f,0x00,0xe0,0x03,0xff,0x03,0x00,0x7c,0x1f,0x7c,0xe0,0x7f,0xff,0x7f, +}; + +static const uint8_t test_tga_color_map_16bpp[] = +{ + 0x00,0x00,0x10,0x00,0x00,0x02,0x10,0x02,0x00,0x40,0x10,0x40,0x00,0x42,0x18,0x63, + 0x78,0x63,0x34,0x7b,0x88,0x00,0x8c,0x00,0x90,0x00,0x94,0x00,0x98,0x00,0x9c,0x00, + 0x00,0x01,0x04,0x01,0x08,0x01,0x0c,0x01,0x10,0x01,0x14,0x01,0x18,0x01,0x1c,0x01, + 0x80,0x01,0x84,0x01,0x88,0x01,0x8c,0x01,0x90,0x01,0x94,0x01,0x98,0x01,0x9c,0x01, + 0x00,0x02,0x04,0x02,0x08,0x02,0x0c,0x02,0x10,0x02,0x14,0x02,0x18,0x02,0x1c,0x02, + 0x80,0x02,0x84,0x02,0x88,0x02,0x8c,0x02,0x90,0x02,0x94,0x02,0x98,0x02,0x9c,0x02, + 0x00,0x03,0x04,0x03,0x08,0x03,0x0c,0x03,0x10,0x03,0x14,0x03,0x18,0x03,0x1c,0x03, + 0x80,0x03,0x84,0x03,0x88,0x03,0x8c,0x03,0x90,0x03,0x94,0x03,0x98,0x03,0x9c,0x03, + 0x00,0x20,0x04,0x20,0x08,0x20,0x0c,0x20,0x10,0x20,0x14,0x20,0x18,0x20,0x1c,0x20, + 0x80,0x20,0x84,0x20,0x88,0x20,0x8c,0x20,0x90,0x20,0x94,0x20,0x98,0x20,0x9c,0x20, + 0x00,0x21,0x04,0x21,0x08,0x21,0x0c,0x21,0x10,0x21,0x14,0x21,0x18,0x21,0x1c,0x21, + 0x80,0x21,0x84,0x21,0x88,0x21,0x8c,0x21,0x90,0x21,0x94,0x21,0x98,0x21,0x9c,0x21, + 0x00,0x22,0x04,0x22,0x08,0x22,0x0c,0x22,0x10,0x22,0x14,0x22,0x18,0x22,0x1c,0x22, + 0x80,0x22,0x84,0x22,0x88,0x22,0x8c,0x22,0x90,0x22,0x94,0x22,0x98,0x22,0x9c,0x22, + 0x00,0x23,0x04,0x23,0x08,0x23,0x0c,0x23,0x10,0x23,0x14,0x23,0x18,0x23,0x1c,0x23, + 0x80,0x23,0x84,0x23,0x88,0x23,0x8c,0x23,0x90,0x23,0x94,0x23,0x98,0x23,0x9c,0x23, + 0x00,0xc0,0x04,0xc0,0x08,0xc0,0x0c,0xc0,0x10,0xc0,0x14,0xc0,0x18,0xc0,0x1c,0xc0, + 0x80,0xc0,0x84,0xc0,0x88,0xc0,0x8c,0xc0,0x90,0xc0,0x94,0xc0,0x98,0xc0,0x9c,0xc0, + 0x00,0xc1,0x04,0xc1,0x08,0xc1,0x0c,0xc1,0x10,0xc1,0x14,0xc1,0x18,0xc1,0x1c,0xc1, + 0x80,0xc1,0x84,0xc1,0x88,0xc1,0x8c,0xc1,0x90,0xc1,0x94,0xc1,0x98,0xc1,0x9c,0xc1, + 0x00,0xc2,0x04,0xc2,0x08,0xc2,0x0c,0xc2,0x10,0xc2,0x14,0xc2,0x18,0xc2,0x1c,0xc2, + 0x80,0xc2,0x84,0xc2,0x88,0xc2,0x8c,0xc2,0x90,0xc2,0x94,0xc2,0x98,0xc2,0x9c,0xc2, + 0x00,0xc3,0x04,0xc3,0x08,0xc3,0x0c,0xc3,0x10,0xc3,0x14,0xc3,0x18,0xc3,0x1c,0xc3, + 0x80,0xc3,0x84,0xc3,0x88,0xc3,0x8c,0xc3,0x90,0xc3,0x94,0xc3,0x98,0xc3,0x9c,0xc3, + 0x00,0xe0,0x04,0xe0,0x08,0xe0,0x0c,0xe0,0x10,0xe0,0x14,0xe0,0x18,0xe0,0x1c,0xe0, + 0x80,0xe0,0x84,0xe0,0x88,0xe0,0x8c,0xe0,0x90,0xe0,0x94,0xe0,0x98,0xe0,0x9c,0xe0, + 0x00,0xe1,0x04,0xe1,0x08,0xe1,0x0c,0xe1,0x10,0xe1,0x14,0xe1,0x18,0xe1,0x1c,0xe1, + 0x80,0xe1,0x84,0xe1,0x88,0xe1,0x8c,0xe1,0x90,0xe1,0x94,0xe1,0x98,0xe1,0x9c,0xe1, + 0x00,0xe2,0x04,0xe2,0x08,0xe2,0x0c,0xe2,0x10,0xe2,0x14,0xe2,0x18,0xe2,0x1c,0xe2, + 0x80,0xe2,0x84,0xe2,0x88,0xe2,0x8c,0xe2,0x90,0xe2,0x94,0xe2,0x98,0xe2,0x9c,0xe2, + 0x00,0xe3,0x04,0xe3,0x08,0xe3,0x0c,0xe3,0x10,0xe3,0x14,0xe3,0xff,0xfb,0x94,0xd2, + 0x10,0xc2,0x1f,0x80,0xe0,0x83,0xff,0x83,0x00,0xfc,0x1f,0xfc,0xe0,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_24bpp[] = +{ + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0x80, + 0x00,0x80,0x00,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xdc,0xc0,0xa6,0xca,0xf0,0x40,0x20, + 0x00,0x60,0x20,0x00,0x80,0x20,0x00,0xa0,0x20,0x00,0xc0,0x20,0x00,0xe0,0x20,0x00, + 0x00,0x40,0x00,0x20,0x40,0x00,0x40,0x40,0x00,0x60,0x40,0x00,0x80,0x40,0x00,0xa0, + 0x40,0x00,0xc0,0x40,0x00,0xe0,0x40,0x00,0x00,0x60,0x00,0x20,0x60,0x00,0x40,0x60, + 0x00,0x60,0x60,0x00,0x80,0x60,0x00,0xa0,0x60,0x00,0xc0,0x60,0x00,0xe0,0x60,0x00, + 0x00,0x80,0x00,0x20,0x80,0x00,0x40,0x80,0x00,0x60,0x80,0x00,0x80,0x80,0x00,0xa0, + 0x80,0x00,0xc0,0x80,0x00,0xe0,0x80,0x00,0x00,0xa0,0x00,0x20,0xa0,0x00,0x40,0xa0, + 0x00,0x60,0xa0,0x00,0x80,0xa0,0x00,0xa0,0xa0,0x00,0xc0,0xa0,0x00,0xe0,0xa0,0x00, + 0x00,0xc0,0x00,0x20,0xc0,0x00,0x40,0xc0,0x00,0x60,0xc0,0x00,0x80,0xc0,0x00,0xa0, + 0xc0,0x00,0xc0,0xc0,0x00,0xe0,0xc0,0x00,0x00,0xe0,0x00,0x20,0xe0,0x00,0x40,0xe0, + 0x00,0x60,0xe0,0x00,0x80,0xe0,0x00,0xa0,0xe0,0x00,0xc0,0xe0,0x00,0xe0,0xe0,0x00, + 0x00,0x00,0x40,0x20,0x00,0x40,0x40,0x00,0x40,0x60,0x00,0x40,0x80,0x00,0x40,0xa0, + 0x00,0x40,0xc0,0x00,0x40,0xe0,0x00,0x40,0x00,0x20,0x40,0x20,0x20,0x40,0x40,0x20, + 0x40,0x60,0x20,0x40,0x80,0x20,0x40,0xa0,0x20,0x40,0xc0,0x20,0x40,0xe0,0x20,0x40, + 0x00,0x40,0x40,0x20,0x40,0x40,0x40,0x40,0x40,0x60,0x40,0x40,0x80,0x40,0x40,0xa0, + 0x40,0x40,0xc0,0x40,0x40,0xe0,0x40,0x40,0x00,0x60,0x40,0x20,0x60,0x40,0x40,0x60, + 0x40,0x60,0x60,0x40,0x80,0x60,0x40,0xa0,0x60,0x40,0xc0,0x60,0x40,0xe0,0x60,0x40, + 0x00,0x80,0x40,0x20,0x80,0x40,0x40,0x80,0x40,0x60,0x80,0x40,0x80,0x80,0x40,0xa0, + 0x80,0x40,0xc0,0x80,0x40,0xe0,0x80,0x40,0x00,0xa0,0x40,0x20,0xa0,0x40,0x40,0xa0, + 0x40,0x60,0xa0,0x40,0x80,0xa0,0x40,0xa0,0xa0,0x40,0xc0,0xa0,0x40,0xe0,0xa0,0x40, + 0x00,0xc0,0x40,0x20,0xc0,0x40,0x40,0xc0,0x40,0x60,0xc0,0x40,0x80,0xc0,0x40,0xa0, + 0xc0,0x40,0xc0,0xc0,0x40,0xe0,0xc0,0x40,0x00,0xe0,0x40,0x20,0xe0,0x40,0x40,0xe0, + 0x40,0x60,0xe0,0x40,0x80,0xe0,0x40,0xa0,0xe0,0x40,0xc0,0xe0,0x40,0xe0,0xe0,0x40, + 0x00,0x00,0x80,0x20,0x00,0x80,0x40,0x00,0x80,0x60,0x00,0x80,0x80,0x00,0x80,0xa0, + 0x00,0x80,0xc0,0x00,0x80,0xe0,0x00,0x80,0x00,0x20,0x80,0x20,0x20,0x80,0x40,0x20, + 0x80,0x60,0x20,0x80,0x80,0x20,0x80,0xa0,0x20,0x80,0xc0,0x20,0x80,0xe0,0x20,0x80, + 0x00,0x40,0x80,0x20,0x40,0x80,0x40,0x40,0x80,0x60,0x40,0x80,0x80,0x40,0x80,0xa0, + 0x40,0x80,0xc0,0x40,0x80,0xe0,0x40,0x80,0x00,0x60,0x80,0x20,0x60,0x80,0x40,0x60, + 0x80,0x60,0x60,0x80,0x80,0x60,0x80,0xa0,0x60,0x80,0xc0,0x60,0x80,0xe0,0x60,0x80, + 0x00,0x80,0x80,0x20,0x80,0x80,0x40,0x80,0x80,0x60,0x80,0x80,0x80,0x80,0x80,0xa0, + 0x80,0x80,0xc0,0x80,0x80,0xe0,0x80,0x80,0x00,0xa0,0x80,0x20,0xa0,0x80,0x40,0xa0, + 0x80,0x60,0xa0,0x80,0x80,0xa0,0x80,0xa0,0xa0,0x80,0xc0,0xa0,0x80,0xe0,0xa0,0x80, + 0x00,0xc0,0x80,0x20,0xc0,0x80,0x40,0xc0,0x80,0x60,0xc0,0x80,0x80,0xc0,0x80,0xa0, + 0xc0,0x80,0xc0,0xc0,0x80,0xe0,0xc0,0x80,0x00,0xe0,0x80,0x20,0xe0,0x80,0x40,0xe0, + 0x80,0x60,0xe0,0x80,0x80,0xe0,0x80,0xa0,0xe0,0x80,0xc0,0xe0,0x80,0xe0,0xe0,0x80, + 0x00,0x00,0xc0,0x20,0x00,0xc0,0x40,0x00,0xc0,0x60,0x00,0xc0,0x80,0x00,0xc0,0xa0, + 0x00,0xc0,0xc0,0x00,0xc0,0xe0,0x00,0xc0,0x00,0x20,0xc0,0x20,0x20,0xc0,0x40,0x20, + 0xc0,0x60,0x20,0xc0,0x80,0x20,0xc0,0xa0,0x20,0xc0,0xc0,0x20,0xc0,0xe0,0x20,0xc0, + 0x00,0x40,0xc0,0x20,0x40,0xc0,0x40,0x40,0xc0,0x60,0x40,0xc0,0x80,0x40,0xc0,0xa0, + 0x40,0xc0,0xc0,0x40,0xc0,0xe0,0x40,0xc0,0x00,0x60,0xc0,0x20,0x60,0xc0,0x40,0x60, + 0xc0,0x60,0x60,0xc0,0x80,0x60,0xc0,0xa0,0x60,0xc0,0xc0,0x60,0xc0,0xe0,0x60,0xc0, + 0x00,0x80,0xc0,0x20,0x80,0xc0,0x40,0x80,0xc0,0x60,0x80,0xc0,0x80,0x80,0xc0,0xa0, + 0x80,0xc0,0xc0,0x80,0xc0,0xe0,0x80,0xc0,0x00,0xa0,0xc0,0x20,0xa0,0xc0,0x40,0xa0, + 0xc0,0x60,0xa0,0xc0,0x80,0xa0,0xc0,0xa0,0xa0,0xc0,0xc0,0xa0,0xc0,0xe0,0xa0,0xc0, + 0x00,0xc0,0xc0,0x20,0xc0,0xc0,0x40,0xc0,0xc0,0x60,0xc0,0xc0,0x80,0xc0,0xc0,0xa0, + 0xc0,0xc0,0xff,0xfb,0xf0,0xa0,0xa0,0xa4,0x80,0x80,0x80,0xff,0x00,0x00,0x00,0xff, + 0x00,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_32bpp[] = +{ + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x01,0x00,0x80,0x00,0x02,0x80,0x80,0x00,0x03, + 0x00,0x00,0x80,0x04,0x80,0x00,0x80,0x05,0x00,0x80,0x80,0x06,0xc0,0xc0,0xc0,0x07, + 0xc0,0xdc,0xc0,0x08,0xa6,0xca,0xf0,0x09,0x40,0x20,0x00,0x0a,0x60,0x20,0x00,0x0b, + 0x80,0x20,0x00,0x0c,0xa0,0x20,0x00,0x0d,0xc0,0x20,0x00,0x0e,0xe0,0x20,0x00,0x0f, + 0x00,0x40,0x00,0x10,0x20,0x40,0x00,0x11,0x40,0x40,0x00,0x12,0x60,0x40,0x00,0x13, + 0x80,0x40,0x00,0x14,0xa0,0x40,0x00,0x15,0xc0,0x40,0x00,0x16,0xe0,0x40,0x00,0x17, + 0x00,0x60,0x00,0x18,0x20,0x60,0x00,0x19,0x40,0x60,0x00,0x1a,0x60,0x60,0x00,0x1b, + 0x80,0x60,0x00,0x1c,0xa0,0x60,0x00,0x1d,0xc0,0x60,0x00,0x1e,0xe0,0x60,0x00,0x1f, + 0x00,0x80,0x00,0x20,0x20,0x80,0x00,0x21,0x40,0x80,0x00,0x22,0x60,0x80,0x00,0x23, + 0x80,0x80,0x00,0x24,0xa0,0x80,0x00,0x25,0xc0,0x80,0x00,0x26,0xe0,0x80,0x00,0x27, + 0x00,0xa0,0x00,0x28,0x20,0xa0,0x00,0x29,0x40,0xa0,0x00,0x2a,0x60,0xa0,0x00,0x2b, + 0x80,0xa0,0x00,0x2c,0xa0,0xa0,0x00,0x2d,0xc0,0xa0,0x00,0x2e,0xe0,0xa0,0x00,0x2f, + 0x00,0xc0,0x00,0x30,0x20,0xc0,0x00,0x31,0x40,0xc0,0x00,0x32,0x60,0xc0,0x00,0x33, + 0x80,0xc0,0x00,0x34,0xa0,0xc0,0x00,0x35,0xc0,0xc0,0x00,0x36,0xe0,0xc0,0x00,0x37, + 0x00,0xe0,0x00,0x38,0x20,0xe0,0x00,0x39,0x40,0xe0,0x00,0x3a,0x60,0xe0,0x00,0x3b, + 0x80,0xe0,0x00,0x3c,0xa0,0xe0,0x00,0x3d,0xc0,0xe0,0x00,0x3e,0xe0,0xe0,0x00,0x3f, + 0x00,0x00,0x40,0x40,0x20,0x00,0x40,0x41,0x40,0x00,0x40,0x42,0x60,0x00,0x40,0x43, + 0x80,0x00,0x40,0x44,0xa0,0x00,0x40,0x45,0xc0,0x00,0x40,0x46,0xe0,0x00,0x40,0x47, + 0x00,0x20,0x40,0x48,0x20,0x20,0x40,0x49,0x40,0x20,0x40,0x4a,0x60,0x20,0x40,0x4b, + 0x80,0x20,0x40,0x4c,0xa0,0x20,0x40,0x4d,0xc0,0x20,0x40,0x4e,0xe0,0x20,0x40,0x4f, + 0x00,0x40,0x40,0x50,0x20,0x40,0x40,0x51,0x40,0x40,0x40,0x52,0x60,0x40,0x40,0x53, + 0x80,0x40,0x40,0x54,0xa0,0x40,0x40,0x55,0xc0,0x40,0x40,0x56,0xe0,0x40,0x40,0x57, + 0x00,0x60,0x40,0x58,0x20,0x60,0x40,0x59,0x40,0x60,0x40,0x5a,0x60,0x60,0x40,0x5b, + 0x80,0x60,0x40,0x5c,0xa0,0x60,0x40,0x5d,0xc0,0x60,0x40,0x5e,0xe0,0x60,0x40,0x5f, + 0x00,0x80,0x40,0x60,0x20,0x80,0x40,0x61,0x40,0x80,0x40,0x62,0x60,0x80,0x40,0x63, + 0x80,0x80,0x40,0x64,0xa0,0x80,0x40,0x65,0xc0,0x80,0x40,0x66,0xe0,0x80,0x40,0x67, + 0x00,0xa0,0x40,0x68,0x20,0xa0,0x40,0x69,0x40,0xa0,0x40,0x6a,0x60,0xa0,0x40,0x6b, + 0x80,0xa0,0x40,0x6c,0xa0,0xa0,0x40,0x6d,0xc0,0xa0,0x40,0x6e,0xe0,0xa0,0x40,0x6f, + 0x00,0xc0,0x40,0x70,0x20,0xc0,0x40,0x71,0x40,0xc0,0x40,0x72,0x60,0xc0,0x40,0x73, + 0x80,0xc0,0x40,0x74,0xa0,0xc0,0x40,0x75,0xc0,0xc0,0x40,0x76,0xe0,0xc0,0x40,0x77, + 0x00,0xe0,0x40,0x78,0x20,0xe0,0x40,0x79,0x40,0xe0,0x40,0x7a,0x60,0xe0,0x40,0x7b, + 0x80,0xe0,0x40,0x7c,0xa0,0xe0,0x40,0x7d,0xc0,0xe0,0x40,0x7e,0xe0,0xe0,0x40,0x7f, + 0x00,0x00,0x80,0x80,0x20,0x00,0x80,0x81,0x40,0x00,0x80,0x82,0x60,0x00,0x80,0x83, + 0x80,0x00,0x80,0x84,0xa0,0x00,0x80,0x85,0xc0,0x00,0x80,0x86,0xe0,0x00,0x80,0x87, + 0x00,0x20,0x80,0x88,0x20,0x20,0x80,0x89,0x40,0x20,0x80,0x8a,0x60,0x20,0x80,0x8b, + 0x80,0x20,0x80,0x8c,0xa0,0x20,0x80,0x8d,0xc0,0x20,0x80,0x8e,0xe0,0x20,0x80,0x8f, + 0x00,0x40,0x80,0x90,0x20,0x40,0x80,0x91,0x40,0x40,0x80,0x92,0x60,0x40,0x80,0x93, + 0x80,0x40,0x80,0x94,0xa0,0x40,0x80,0x95,0xc0,0x40,0x80,0x96,0xe0,0x40,0x80,0x97, + 0x00,0x60,0x80,0x98,0x20,0x60,0x80,0x99,0x40,0x60,0x80,0x9a,0x60,0x60,0x80,0x9b, + 0x80,0x60,0x80,0x9c,0xa0,0x60,0x80,0x9d,0xc0,0x60,0x80,0x9e,0xe0,0x60,0x80,0x9f, + 0x00,0x80,0x80,0xa0,0x20,0x80,0x80,0xa1,0x40,0x80,0x80,0xa2,0x60,0x80,0x80,0xa3, + 0x80,0x80,0x80,0xa4,0xa0,0x80,0x80,0xa5,0xc0,0x80,0x80,0xa6,0xe0,0x80,0x80,0xa7, + 0x00,0xa0,0x80,0xa8,0x20,0xa0,0x80,0xa9,0x40,0xa0,0x80,0xaa,0x60,0xa0,0x80,0xab, + 0x80,0xa0,0x80,0xac,0xa0,0xa0,0x80,0xad,0xc0,0xa0,0x80,0xae,0xe0,0xa0,0x80,0xaf, + 0x00,0xc0,0x80,0xb0,0x20,0xc0,0x80,0xb1,0x40,0xc0,0x80,0xb2,0x60,0xc0,0x80,0xb3, + 0x80,0xc0,0x80,0xb4,0xa0,0xc0,0x80,0xb5,0xc0,0xc0,0x80,0xb6,0xe0,0xc0,0x80,0xb7, + 0x00,0xe0,0x80,0xb8,0x20,0xe0,0x80,0xb9,0x40,0xe0,0x80,0xba,0x60,0xe0,0x80,0xbb, + 0x80,0xe0,0x80,0xbc,0xa0,0xe0,0x80,0xbd,0xc0,0xe0,0x80,0xbe,0xe0,0xe0,0x80,0xbf, + 0x00,0x00,0xc0,0xc0,0x20,0x00,0xc0,0xc1,0x40,0x00,0xc0,0xc2,0x60,0x00,0xc0,0xc3, + 0x80,0x00,0xc0,0xc4,0xa0,0x00,0xc0,0xc5,0xc0,0x00,0xc0,0xc6,0xe0,0x00,0xc0,0xc7, + 0x00,0x20,0xc0,0xc8,0x20,0x20,0xc0,0xc9,0x40,0x20,0xc0,0xca,0x60,0x20,0xc0,0xcb, + 0x80,0x20,0xc0,0xcc,0xa0,0x20,0xc0,0xcd,0xc0,0x20,0xc0,0xce,0xe0,0x20,0xc0,0xcf, + 0x00,0x40,0xc0,0xd0,0x20,0x40,0xc0,0xd1,0x40,0x40,0xc0,0xd2,0x60,0x40,0xc0,0xd3, + 0x80,0x40,0xc0,0xd4,0xa0,0x40,0xc0,0xd5,0xc0,0x40,0xc0,0xd6,0xe0,0x40,0xc0,0xd7, + 0x00,0x60,0xc0,0xd8,0x20,0x60,0xc0,0xd9,0x40,0x60,0xc0,0xda,0x60,0x60,0xc0,0xdb, + 0x80,0x60,0xc0,0xdc,0xa0,0x60,0xc0,0xdd,0xc0,0x60,0xc0,0xde,0xe0,0x60,0xc0,0xdf, + 0x00,0x80,0xc0,0xe0,0x20,0x80,0xc0,0xe1,0x40,0x80,0xc0,0xe2,0x60,0x80,0xc0,0xe3, + 0x80,0x80,0xc0,0xe4,0xa0,0x80,0xc0,0xe5,0xc0,0x80,0xc0,0xe6,0xe0,0x80,0xc0,0xe7, + 0x00,0xa0,0xc0,0xe8,0x20,0xa0,0xc0,0xe9,0x40,0xa0,0xc0,0xea,0x60,0xa0,0xc0,0xeb, + 0x80,0xa0,0xc0,0xec,0xa0,0xa0,0xc0,0xed,0xc0,0xa0,0xc0,0xee,0xe0,0xa0,0xc0,0xef, + 0x00,0xc0,0xc0,0xf0,0x20,0xc0,0xc0,0xf1,0x40,0xc0,0xc0,0xf2,0x60,0xc0,0xc0,0xf3, + 0x80,0xc0,0xc0,0xf4,0xa0,0xc0,0xc0,0xf5,0xff,0xfb,0xf0,0xf6,0xa0,0xa0,0xa4,0xf7, + 0x80,0x80,0x80,0xf8,0xff,0x00,0x00,0xf9,0x00,0xff,0x00,0xfa,0xff,0xff,0x00,0xfb, + 0x00,0x00,0xff,0xfc,0xff,0x00,0xff,0xfd,0x00,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_index_4_4[] = +{ + 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xff, +}; + +static const uint8_t test_tga_color_map_index_4_4_rle[] = +{ + 0x83,0x10,0x83,0x20,0x03,0x80,0x90,0xa0,0xb0,0x03,0xc0,0xd0,0xe0,0xff, +}; + +static const uint8_t test_tga_true_color_15bpp_4_4[] = +{ + 0x00,0x04,0x42,0x0c,0x84,0x14,0xc6,0x1c,0x08,0x25,0x4a,0x2d,0x8c,0x35,0xce,0x3d, + 0x10,0x46,0x52,0x4e,0x94,0x56,0xd6,0x5e,0x18,0x67,0x5a,0x6f,0x9c,0x77,0xde,0x7f, +}; + +static const uint8_t test_tga_true_color_15bpp_4_4_rle[] = +{ + 0x03,0x00,0x04,0x42,0x0c,0x84,0x14,0xc6,0x1c,0x81,0x08,0x25,0x00,0x8c,0x35,0x00, + 0xce,0x3d,0x03,0x10,0x46,0x52,0x4e,0x94,0x56,0xd6,0x5e,0x03,0x18,0x67,0x5a,0x6f, + 0x9c,0x77,0xde,0x7f, +}; + +static const uint8_t test_tga_true_color_16bpp_4_4[] = +{ + 0x00,0x04,0x42,0x0c,0x84,0x14,0xc6,0x1c,0x08,0x25,0x4a,0x2d,0x8c,0x35,0xce,0x3d, + 0x10,0xc6,0x52,0xce,0x94,0xd6,0xd6,0xde,0x18,0xe7,0x5a,0xef,0x9c,0xf7,0xde,0xff, +}; + +static const uint8_t test_tga_true_color_16bpp_4_4_rle[] = +{ + 0x03,0x00,0x04,0x42,0x0c,0x84,0x14,0xc6,0x1c,0x81,0x08,0x25,0x00,0x8c,0x35,0x00, + 0xce,0x3d,0x03,0x10,0xc6,0x52,0xce,0x94,0xd6,0xd6,0xde,0x03,0x18,0xe7,0x5a,0xef, + 0x9c,0xf7,0xde,0xff, +}; + +static const uint8_t test_tga_true_color_24bpp_4_4[] = +{ + 0x00,0x04,0x08,0x10,0x14,0x18,0x20,0x24,0x28,0x30,0x34,0x38,0x40,0x44,0x48,0x50, + 0x54,0x58,0x60,0x64,0x68,0x70,0x74,0x78,0x80,0x84,0x88,0x90,0x94,0x98,0xa0,0xa4, + 0xa8,0xb0,0xb4,0xb8,0xc0,0xc4,0xc8,0xd0,0xd4,0xd8,0xe0,0xe4,0xe8,0xf0,0xf4,0xf8, +}; + +static const uint8_t test_tga_true_color_24bpp_4_4_rle[] = +{ + 0x03,0x00,0x04,0x08,0x10,0x14,0x18,0x20,0x24,0x28,0x30,0x34,0x38,0x81,0x40,0x44, + 0x48,0x00,0x60,0x64,0x68,0x00,0x70,0x74,0x78,0x03,0x80,0x84,0x88,0x90,0x94,0x98, + 0xa0,0xa4,0xa8,0xb0,0xb4,0xb8,0x03,0xc0,0xc4,0xc8,0xd0,0xd4,0xd8,0xe0,0xe4,0xe8, + 0xf0,0xf4,0xf8, +}; + +static const uint8_t test_tga_true_color_32bpp_4_4[] = +{ + 0x08,0x04,0x00,0x0c,0x18,0x14,0x10,0x1c,0x28,0x24,0x20,0x2c,0x38,0x34,0x30,0x3c, + 0x48,0x44,0x40,0x4c,0x58,0x54,0x50,0x5c,0x68,0x64,0x60,0x6c,0x78,0x74,0x70,0x7c, + 0x88,0x84,0x80,0x8c,0x98,0x94,0x90,0x9c,0xa8,0xa4,0xa0,0xac,0xb8,0xb4,0xb0,0xbc, + 0xc8,0xc4,0xc0,0xcc,0xd8,0xd4,0xd0,0xdc,0xe8,0xe4,0xe0,0xec,0xf8,0xf4,0xf0,0xfc, +}; + +static const uint8_t test_tga_true_color_32bpp_4_4_rle[] = +{ + 0x03,0x08,0x04,0x00,0x0c,0x18,0x14,0x10,0x1c,0x28,0x24,0x20,0x2c,0x38,0x34,0x30, + 0x3c,0x81,0x48,0x44,0x40,0x4c,0x00,0x68,0x64,0x60,0x6c,0x00,0x78,0x74,0x70,0x7c, + 0x03,0x88,0x84,0x80,0x8c,0x98,0x94,0x90,0x9c,0xa8,0xa4,0xa0,0xac,0xb8,0xb4,0xb0, + 0xbc,0x03,0xc8,0xc4,0xc0,0xcc,0xd8,0xd4,0xd0,0xdc,0xe8,0xe4,0xe0,0xec,0xf8,0xf4, + 0xf0,0xfc, +}; + +static const uint8_t test_tga_grayscale_8bpp_4_4[] = +{ + 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0, +}; + +static const uint8_t test_tga_grayscale_8bpp_4_4_rle[] = +{ + 0x03,0x00,0x10,0x20,0x30,0x82,0x40,0x00,0x70,0x03,0x80,0x90,0xa0,0xb0,0x03,0xc0, + 0xd0,0xe0,0xf0, +}; + +/* Expected is stored as bottom to top. */ +static const uint8_t test_tga_color_map_15bpp_expected[] = +{ + 0x00,0x00,0x00,0xff,0x00,0x42,0x00,0xff,0x00,0x84,0x00,0xff,0x00,0xc6,0x00,0xff, + 0x42,0x00,0x00,0xff,0x42,0x42,0x00,0xff,0x42,0x84,0x00,0xff,0x42,0xc6,0x00,0xff, + 0x84,0x00,0x00,0xff,0x84,0x42,0x00,0xff,0x84,0x84,0x00,0xff,0x84,0xc6,0x00,0xff, + 0xc6,0x00,0x00,0xff,0xc6,0x42,0x00,0xff,0xc6,0x84,0x00,0xff,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_15bpp_rle_expected[] = +{ + 0x00,0x42,0x00,0xff,0x00,0x42,0x00,0xff,0x00,0x42,0x00,0xff,0x00,0x42,0x00,0xff, + 0x00,0x84,0x00,0xff,0x00,0x84,0x00,0xff,0x00,0x84,0x00,0xff,0x00,0x84,0x00,0xff, + 0x84,0x00,0x00,0xff,0x84,0x42,0x00,0xff,0x84,0x84,0x00,0xff,0x84,0xc6,0x00,0xff, + 0xc6,0x00,0x00,0xff,0xc6,0x42,0x00,0xff,0xc6,0x84,0x00,0xff,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_16bpp_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x84,0x00,0x00,0x00,0xc6,0x00,0x00, + 0x42,0x00,0x00,0x00,0x42,0x42,0x00,0x00,0x42,0x84,0x00,0x00,0x42,0xc6,0x00,0x00, + 0x84,0x00,0x00,0xff,0x84,0x42,0x00,0xff,0x84,0x84,0x00,0xff,0x84,0xc6,0x00,0xff, + 0xc6,0x00,0x00,0xff,0xc6,0x42,0x00,0xff,0xc6,0x84,0x00,0xff,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_24bpp_expected[] = +{ + 0x00,0x00,0x00,0xff,0x00,0x40,0x00,0xff,0x00,0x80,0x00,0xff,0x00,0xc0,0x00,0xff, + 0x40,0x00,0x00,0xff,0x40,0x40,0x00,0xff,0x40,0x80,0x00,0xff,0x40,0xc0,0x00,0xff, + 0x80,0x00,0x00,0xff,0x80,0x40,0x00,0xff,0x80,0x80,0x00,0xff,0x80,0xc0,0x00,0xff, + 0xc0,0x00,0x00,0xff,0xc0,0x40,0x00,0xff,0xc0,0x80,0x00,0xff,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_32bpp_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x80,0x00,0x20,0x00,0xc0,0x00,0x30, + 0x40,0x00,0x00,0x40,0x40,0x40,0x00,0x50,0x40,0x80,0x00,0x60,0x40,0xc0,0x00,0x70, + 0x80,0x00,0x00,0x80,0x80,0x40,0x00,0x90,0x80,0x80,0x00,0xa0,0x80,0xc0,0x00,0xb0, + 0xc0,0x00,0x00,0xc0,0xc0,0x40,0x00,0xd0,0xc0,0x80,0x00,0xe0,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_color_map_half_32bpp_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x80,0x00,0x20,0x00,0xc0,0x00,0x30, + 0x40,0x00,0x00,0x40,0x40,0x40,0x00,0x50,0x40,0x80,0x00,0x60,0x40,0xc0,0x00,0x70, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +static const uint8_t test_tga_true_color_15bpp_rle_expected[] = +{ + 0x00,0x04,0x42,0x0c,0x84,0x14,0xc6,0x1c,0x08,0x25,0x08,0x25,0x8c,0x35,0xce,0x3d, + 0x10,0x46,0x52,0x4e,0x94,0x56,0xd6,0x5e,0x18,0x67,0x5a,0x6f,0x9c,0x77,0xde,0x7f, +}; + +static const uint8_t test_tga_true_color_16bpp_rle_expected[] = +{ + 0x00,0x04,0x42,0x0c,0x84,0x14,0xc6,0x1c,0x08,0x25,0x08,0x25,0x8c,0x35,0xce,0x3d, + 0x10,0xc6,0x52,0xce,0x94,0xd6,0xd6,0xde,0x18,0xe7,0x5a,0xef,0x9c,0xf7,0xde,0xff, +}; + +static const uint8_t test_tga_true_color_24bpp_rle_expected[] = +{ + 0x00,0x04,0x08,0x10,0x14,0x18,0x20,0x24,0x28,0x30,0x34,0x38,0x40,0x44,0x48,0x40, + 0x44,0x48,0x60,0x64,0x68,0x70,0x74,0x78,0x80,0x84,0x88,0x90,0x94,0x98,0xa0,0xa4, + 0xa8,0xb0,0xb4,0xb8,0xc0,0xc4,0xc8,0xd0,0xd4,0xd8,0xe0,0xe4,0xe8,0xf0,0xf4,0xf8, +}; + +static const uint8_t test_tga_true_color_32bpp_rle_expected[] = +{ + 0x08,0x04,0x00,0x0c,0x18,0x14,0x10,0x1c,0x28,0x24,0x20,0x2c,0x38,0x34,0x30,0x3c, + 0x48,0x44,0x40,0x4c,0x48,0x44,0x40,0x4c,0x68,0x64,0x60,0x6c,0x78,0x74,0x70,0x7c, + 0x88,0x84,0x80,0x8c,0x98,0x94,0x90,0x9c,0xa8,0xa4,0xa0,0xac,0xb8,0xb4,0xb0,0xbc, + 0xc8,0xc4,0xc0,0xcc,0xd8,0xd4,0xd0,0xdc,0xe8,0xe4,0xe0,0xec,0xf8,0xf4,0xf0,0xfc, +}; + +static const uint8_t test_tga_grayscale_8bpp_rle_expected[] = +{ + 0x00,0x10,0x20,0x30,0x40,0x40,0x40,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0, +}; + +#define check_tga_surface_load(surface, expected, right_to_left, bottom_to_top, todo) \ + check_tga_surface_load_(__LINE__, surface, expected, right_to_left, bottom_to_top, todo) +static void check_tga_surface_load_(uint32_t line, IDirect3DSurface9 *surface, const uint8_t *expected, BOOL right_to_left, + BOOL bottom_to_top, BOOL todo) +{ + uint32_t x, y, fmt_bpp, fmt_pitch, mismatch_count; + D3DLOCKED_RECT lock_rect; + D3DSURFACE_DESC desc; + HRESULT hr; + + hr = IDirect3DSurface9_GetDesc(surface, &desc); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + fmt_bpp = get_bpp_for_d3dformat(desc.Format); + fmt_pitch = fmt_bpp * desc.Width; + IDirect3DSurface9_LockRect(surface, &lock_rect, NULL, D3DLOCK_READONLY); + mismatch_count = 0; + for (y = 0; y < desc.Height; ++y) + { + const uint32_t expected_row_idx = bottom_to_top ? (desc.Height - y - 1) : y; + const uint8_t *row = ((uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + const uint8_t *expected_row = expected + (fmt_pitch * expected_row_idx); + + for (x = 0; x < desc.Width; ++x) + { + const uint32_t expected_pixel_idx = right_to_left ? (desc.Width - x - 1) : x; + const uint8_t *expected_pixel = expected_row + (fmt_bpp * expected_pixel_idx); + const uint8_t *pixel = row + (fmt_bpp * x); + BOOL pixel_match = !memcmp(pixel, expected_pixel, fmt_bpp); + + if (!pixel_match) + mismatch_count++; + } + } + todo_wine_if(todo) ok_(__FILE__, line)(!mismatch_count, "%u mismatched pixels.\n", mismatch_count); + IDirect3DSurface9_UnlockRect(surface); +} + +static void test_load_surface_from_tga(IDirect3DDevice9 *device) +{ + static const struct + { + struct tga_header header; + const uint8_t *color_map; + uint32_t color_map_size; + const uint8_t *pixels; + uint32_t pixels_size; + + const uint8_t *expected; + BOOL todo_hr; + BOOL todo_surface; + } tga_tests[] = + { + { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 15, 0, 0, 4, 4, 8, 0 }, + test_tga_color_map_15bpp, sizeof(test_tga_color_map_15bpp), + test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), + test_tga_color_map_15bpp_expected, + }, + { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED | IMAGETYPE_RLE, 0, 256, 15, 0, 0, 4, 4, 8, 0 }, + test_tga_color_map_15bpp, sizeof(test_tga_color_map_15bpp), + test_tga_color_map_index_4_4_rle, sizeof(test_tga_color_map_index_4_4_rle), + test_tga_color_map_15bpp_rle_expected + }, + { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 16, 0, 0, 4, 4, 8, 0 }, + test_tga_color_map_16bpp, sizeof(test_tga_color_map_16bpp), + test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), + test_tga_color_map_16bpp_expected, .todo_surface = TRUE + }, + { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 24, 0, 0, 4, 4, 8, 0 }, + test_tga_color_map_24bpp, sizeof(test_tga_color_map_24bpp), + test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), + test_tga_color_map_24bpp_expected, .todo_surface = TRUE + }, + { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 32, 0, 0, 4, 4, 8, 0 }, + test_tga_color_map_32bpp, sizeof(test_tga_color_map_32bpp), + test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), + test_tga_color_map_32bpp_expected, .todo_surface = TRUE + }, + { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 128, 32, 0, 0, 4, 4, 8, 0 }, + test_tga_color_map_32bpp, sizeof(test_tga_color_map_32bpp) / 2, + test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), + test_tga_color_map_half_32bpp_expected, .todo_surface = TRUE + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, + NULL, 0, + test_tga_true_color_15bpp_4_4, sizeof(test_tga_true_color_15bpp_4_4), + test_tga_true_color_15bpp_4_4, .todo_hr = TRUE + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, + NULL, 0, + test_tga_true_color_15bpp_4_4_rle, sizeof(test_tga_true_color_15bpp_4_4_rle), + test_tga_true_color_15bpp_rle_expected, .todo_hr = TRUE + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, + NULL, 0, + test_tga_true_color_16bpp_4_4, sizeof(test_tga_true_color_16bpp_4_4), + test_tga_true_color_16bpp_4_4, .todo_surface = TRUE + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, + NULL, 0, + test_tga_true_color_16bpp_4_4_rle, sizeof(test_tga_true_color_16bpp_4_4_rle), + test_tga_true_color_16bpp_rle_expected, .todo_surface = TRUE + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 24, 0 }, + NULL, 0, + test_tga_true_color_24bpp_4_4, sizeof(test_tga_true_color_24bpp_4_4), + test_tga_true_color_24bpp_4_4, + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 24, 0 }, + NULL, 0, + test_tga_true_color_24bpp_4_4_rle, sizeof(test_tga_true_color_24bpp_4_4_rle), + test_tga_true_color_24bpp_rle_expected + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 32, 0 }, + NULL, 0, + test_tga_true_color_32bpp_4_4, sizeof(test_tga_true_color_32bpp_4_4), + test_tga_true_color_32bpp_4_4, + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 32, 0 }, + NULL, 0, + test_tga_true_color_32bpp_4_4_rle, sizeof(test_tga_true_color_32bpp_4_4_rle), + test_tga_true_color_32bpp_rle_expected + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_GRAYSCALE, 0, 0, 0, 0, 0, 4, 4, 8, 0 }, + NULL, 0, + test_tga_grayscale_8bpp_4_4, sizeof(test_tga_grayscale_8bpp_4_4), + test_tga_grayscale_8bpp_4_4 + }, + { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_GRAYSCALE | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 8, 0 }, + NULL, 0, + test_tga_grayscale_8bpp_4_4_rle, sizeof(test_tga_grayscale_8bpp_4_4_rle), + test_tga_grayscale_8bpp_rle_expected + }, + }; + static const uint8_t rle_test_bits[] = { 15, 16, 24, 32 }; + struct + { + struct tga_header header; + uint8_t data[4096 * 1024]; + } *tga; + IDirect3DSurface9 *surface; + uint32_t i; + HRESULT hr; + + if (!(tga = calloc(1, sizeof(*tga)))) + { + skip("Failed to allocate memory.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tga_tests); ++i) + { + const uint32_t file_size = sizeof(tga->header) + tga_tests[i].color_map_size + tga_tests[i].pixels_size; + D3DFORMAT surface_fmt; + D3DXIMAGE_INFO info; + + winetest_push_context("Test %u", i); + + tga->header = tga_tests[i].header; + if (tga_tests[i].color_map) + memcpy(tga->data, tga_tests[i].color_map, tga_tests[i].color_map_size); + memcpy(tga->data + tga_tests[i].color_map_size, tga_tests[i].pixels, tga_tests[i].pixels_size); + + hr = D3DXGetImageInfoFromFileInMemory(tga, file_size, &info); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + surface_fmt = (info.Format == D3DFMT_P8) ? D3DFMT_A8B8G8R8 : info.Format; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, info.Width, info.Height, surface_fmt, D3DPOOL_SCRATCH, + &surface, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* + * Unlike D3DXGetImageInfo(), file size must be valid when loading + * image data. + */ + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size - 1, NULL, D3DX_FILTER_NONE, 0, NULL); + ok(hr == D3DXERR_INVALIDDATA, "Unexpected hr %#lx.\n", hr); + + /* Read as default, bottom to top, left to right. */ + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + todo_wine_if(tga_tests[i].todo_hr) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE, tga_tests[i].todo_surface); + + /* Read as top to bottom, left to right. */ + tga->header.image_descriptor = IMAGE_TOPTOBOTTOM; + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + todo_wine_if(tga_tests[i].todo_hr) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + check_tga_surface_load(surface, tga_tests[i].expected, FALSE, FALSE, tga_tests[i].todo_surface); + + /* Read as bottom to top, right to left. */ + tga->header.image_descriptor = IMAGE_RIGHTTOLEFT; + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + check_tga_surface_load(surface, tga_tests[i].expected, TRUE, TRUE, FALSE); + + /* Read as top to bottom, right to left. */ + tga->header.image_descriptor = IMAGE_TOPTOBOTTOM | IMAGE_RIGHTTOLEFT; + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + check_tga_surface_load(surface, tga_tests[i].expected, TRUE, FALSE, FALSE); + + check_release((IUnknown *)surface, 0); + winetest_pop_context(); + } + + /* + * Test RLE behavior. RLE packets cannot cross row boundaries. + */ + for (i = 0; i < ARRAY_SIZE(rle_test_bits); ++i) + { + const struct tga_header rle_hdr = { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, + 4, 2, rle_test_bits[i], IMAGE_TOPTOBOTTOM }; + const uint32_t packet_size = ((rle_test_bits[i] + 7) / 8) + 1; + uint32_t file_size = sizeof(tga->header); + D3DFORMAT surface_fmt; + D3DXIMAGE_INFO info; + + winetest_push_context("Test %u", i); + + memset(tga->data, 0, sizeof(tga->data)); + tga->header = rle_hdr; + + hr = D3DXGetImageInfoFromFileInMemory(tga, file_size, &info); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + surface_fmt = info.Format; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, info.Width, info.Height, surface_fmt, D3DPOOL_SCRATCH, + &surface, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* + * This packet encodes 8 pixels, but the image has a width of 4. This + * should fail. + */ + tga->data[0] = 0x87; + file_size += packet_size; + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + todo_wine_if(rle_test_bits[i] != 15) ok(hr == D3DXERR_INVALIDDATA, "Unexpected hr %#lx.\n", hr); + + /* Two packets, each containing 4 pixels. This succeeds. */ + tga->data[0] = 0x83; + tga->data[packet_size] = 0x83; + file_size += packet_size; + + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + todo_wine_if(rle_test_bits[i] == 15) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* Second packet with only 2 pixels, doesn't finish the final row. */ + tga->data[packet_size] = 0x82; + hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); + ok(hr == D3DXERR_INVALIDDATA, "Unexpected hr %#lx.\n", hr); + + check_release((IUnknown *)surface, 0); + winetest_pop_context(); + } + + free(tga); +} + static void test_D3DXLoadSurface(IDirect3DDevice9 *device) { HRESULT hr; @@ -2755,6 +3380,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
test_format_conversion(device); test_dxt_premultiplied_alpha(device); + test_load_surface_from_tga(device);
/* cleanup */ if(testdummy_ok) DeleteFileA("testdummy.bmp");
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 41 ++++++++++++++++++++++++++++++----- dlls/d3dx9_36/tests/surface.c | 8 +++---- 2 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index c56310982dc..cc2d2f22c17 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1009,6 +1009,9 @@ static D3DFORMAT d3dx_get_tga_format_for_bpp(uint8_t bpp) #define IMAGETYPE_MASK 0x07 #define IMAGETYPE_RLE 8
+#define IMAGE_RIGHTTOLEFT 0x10 +#define IMAGE_TOPTOBOTTOM 0x20 + #include "pshpack1.h" struct tga_header { @@ -1027,7 +1030,32 @@ struct tga_header }; #include "poppack.h"
-static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image) +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 tga_header *header = (const struct tga_header *)src_data; + const BOOL right_to_left = !!(header->image_descriptor & IMAGE_RIGHTTOLEFT); + const BOOL bottom_to_top = !(header->image_descriptor & IMAGE_TOPTOBOTTOM); + const BOOL is_rle = !!(header->image_type & IMAGETYPE_RLE); + uint32_t row_pitch, slice_pitch; + HRESULT hr; + + if (image->format == D3DFMT_P8 || is_rle || bottom_to_top || right_to_left) + return E_NOTIMPL; + + 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 ((src_header_size + slice_pitch) > src_data_size) + return D3DXERR_INVALIDDATA; + + image->pixels = (uint8_t *)src_data + src_header_size; + return D3D_OK; +} + +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); @@ -1073,6 +1101,9 @@ static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src image->resource_type = D3DRTYPE_TEXTURE; image->image_file_format = D3DXIFF_TGA;
+ if (!(flags & D3DX_IMAGE_INFO_ONLY)) + return d3dx_image_tga_decode(src_data, src_data_size, expected_header_size, image); + return D3D_OK; }
@@ -1101,10 +1132,10 @@ 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); + hr = d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); + if (hr == E_NOTIMPL) + hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, D3DXIFF_TGA, flags); + return hr; }
switch (iff) diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 6653dc91611..567a00b4f05 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1973,7 +1973,7 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, NULL, 0, test_tga_true_color_15bpp_4_4, sizeof(test_tga_true_color_15bpp_4_4), - test_tga_true_color_15bpp_4_4, .todo_hr = TRUE + test_tga_true_color_15bpp_4_4 }, { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, NULL, 0, @@ -1983,7 +1983,7 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, NULL, 0, test_tga_true_color_16bpp_4_4, sizeof(test_tga_true_color_16bpp_4_4), - test_tga_true_color_16bpp_4_4, .todo_surface = TRUE + test_tga_true_color_16bpp_4_4 }, { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, NULL, 0, @@ -2067,9 +2067,9 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device)
/* Read as default, bottom to top, left to right. */ hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].todo_hr) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(tga_tests[i].todo_hr || tga->header.depth == 15) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) - check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE, tga_tests[i].todo_surface); + check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE, tga_tests[i].todo_surface || tga->header.depth == 16);
/* Read as top to bottom, left to right. */ tga->header.image_descriptor = IMAGE_TOPTOBOTTOM;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 45 ++++++++++++++++++++++++++++++++--- dlls/d3dx9_36/tests/surface.c | 8 +++---- 2 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index cc2d2f22c17..1797269eee2 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1036,11 +1036,14 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz const struct tga_header *header = (const struct tga_header *)src_data; const BOOL right_to_left = !!(header->image_descriptor & IMAGE_RIGHTTOLEFT); const BOOL bottom_to_top = !(header->image_descriptor & IMAGE_TOPTOBOTTOM); + const struct pixel_format_desc *fmt_desc = get_format_info(image->format); const BOOL is_rle = !!(header->image_type & IMAGETYPE_RLE); - uint32_t row_pitch, slice_pitch; + uint32_t row_pitch, slice_pitch, i; + uint8_t *img_buf = NULL; + const uint8_t *src_row; HRESULT hr;
- if (image->format == D3DFMT_P8 || is_rle || bottom_to_top || right_to_left) + if (image->format == D3DFMT_P8 || is_rle) return E_NOTIMPL;
hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); @@ -1051,7 +1054,43 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz if ((src_header_size + slice_pitch) > src_data_size) return D3DXERR_INVALIDDATA;
- image->pixels = (uint8_t *)src_data + src_header_size; + if (!bottom_to_top && !right_to_left) + { + image->pixels = (uint8_t *)src_data + src_header_size; + return D3D_OK; + } + + if (!(img_buf = malloc(slice_pitch))) + return E_OUTOFMEMORY; + + src_row = (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 (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); + } + + src_row += row_pitch; + } + + image->image_buf = image->pixels = img_buf; return D3D_OK; }
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 567a00b4f05..2daaba8ba9a 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -2067,9 +2067,9 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device)
/* Read as default, bottom to top, left to right. */ hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].todo_hr || tga->header.depth == 15) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(tga_tests[i].todo_hr) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) - check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE, tga_tests[i].todo_surface || tga->header.depth == 16); + check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE, tga_tests[i].todo_surface);
/* Read as top to bottom, left to right. */ tga->header.image_descriptor = IMAGE_TOPTOBOTTOM; @@ -2081,14 +2081,14 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) /* Read as bottom to top, right to left. */ tga->header.image_descriptor = IMAGE_RIGHTTOLEFT; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(tga_tests[i].color_map || (tga->header.image_type & IMAGETYPE_RLE)) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) check_tga_surface_load(surface, tga_tests[i].expected, TRUE, TRUE, FALSE);
/* Read as top to bottom, right to left. */ tga->header.image_descriptor = IMAGE_TOPTOBOTTOM | IMAGE_RIGHTTOLEFT; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(tga_tests[i].color_map || (tga->header.image_type & IMAGETYPE_RLE)) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) check_tga_surface_load(surface, tga_tests[i].expected, TRUE, FALSE, FALSE);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 76 ++++++++++++++++++++++++++++++----- dlls/d3dx9_36/tests/surface.c | 12 +++--- 2 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 1797269eee2..cfe6e525bff 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1030,6 +1030,44 @@ struct tga_header }; #include "poppack.h"
+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; +} + static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, struct d3dx_image *image) { @@ -1039,11 +1077,11 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz const struct pixel_format_desc *fmt_desc = get_format_info(image->format); const BOOL is_rle = !!(header->image_type & IMAGETYPE_RLE); uint32_t row_pitch, slice_pitch, i; - uint8_t *img_buf = NULL; - const uint8_t *src_row; + uint8_t *img_buf = NULL, *src_row; + const uint8_t *src_pos; HRESULT hr;
- if (image->format == D3DFMT_P8 || is_rle) + if (image->format == D3DFMT_P8) return E_NOTIMPL;
hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); @@ -1051,24 +1089,39 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz return hr;
/* File is too small. */ - if ((src_header_size + slice_pitch) > src_data_size) + if (!is_rle && (src_header_size + slice_pitch) > src_data_size) return D3DXERR_INVALIDDATA;
- if (!bottom_to_top && !right_to_left) + if (!is_rle && !bottom_to_top && !right_to_left) { image->pixels = (uint8_t *)src_data + src_header_size; return D3D_OK; }
- if (!(img_buf = malloc(slice_pitch))) + /* Allocate an extra row to use as a temporary buffer. */ + if (!(img_buf = malloc(slice_pitch + row_pitch))) return E_OUTOFMEMORY;
- src_row = (const uint8_t *)src_data + src_header_size; + src_row = img_buf + slice_pitch; + 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 + { + memcpy(src_row, src_pos, row_pitch); + src_pos += row_pitch; + } + if (right_to_left) { const uint8_t *src_pixel = &src_row[((image->size.width - 1)) * fmt_desc->bytes_per_pixel]; @@ -1086,12 +1139,15 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz { memcpy(dst_row, src_row, row_pitch); } - - src_row += row_pitch; }
image->image_buf = image->pixels = img_buf; - return D3D_OK; + +exit: + if (img_buf && (image->image_buf != img_buf)) + free(img_buf); + + 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) diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 2daaba8ba9a..691c4011fd0 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1978,7 +1978,7 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, NULL, 0, test_tga_true_color_15bpp_4_4_rle, sizeof(test_tga_true_color_15bpp_4_4_rle), - test_tga_true_color_15bpp_rle_expected, .todo_hr = TRUE + test_tga_true_color_15bpp_rle_expected }, { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, NULL, 0, @@ -1988,7 +1988,7 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 16, 0 }, NULL, 0, test_tga_true_color_16bpp_4_4_rle, sizeof(test_tga_true_color_16bpp_4_4_rle), - test_tga_true_color_16bpp_rle_expected, .todo_surface = TRUE + test_tga_true_color_16bpp_rle_expected }, { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 24, 0 }, NULL, 0, @@ -2081,14 +2081,14 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) /* Read as bottom to top, right to left. */ tga->header.image_descriptor = IMAGE_RIGHTTOLEFT; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].color_map || (tga->header.image_type & IMAGETYPE_RLE)) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(tga_tests[i].color_map) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) check_tga_surface_load(surface, tga_tests[i].expected, TRUE, TRUE, FALSE);
/* Read as top to bottom, right to left. */ tga->header.image_descriptor = IMAGE_TOPTOBOTTOM | IMAGE_RIGHTTOLEFT; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].color_map || (tga->header.image_type & IMAGETYPE_RLE)) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + todo_wine_if(tga_tests[i].color_map) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) check_tga_surface_load(surface, tga_tests[i].expected, TRUE, FALSE, FALSE);
@@ -2128,7 +2128,7 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) tga->data[0] = 0x87; file_size += packet_size; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(rle_test_bits[i] != 15) ok(hr == D3DXERR_INVALIDDATA, "Unexpected hr %#lx.\n", hr); + ok(hr == D3DXERR_INVALIDDATA, "Unexpected hr %#lx.\n", hr);
/* Two packets, each containing 4 pixels. This succeeds. */ tga->data[0] = 0x83; @@ -2136,7 +2136,7 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) file_size += packet_size;
hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(rle_test_bits[i] == 15) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
/* Second packet with only 2 pixels, doesn't finish the final row. */ tga->data[packet_size] = 0x82;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 54 ++++++++++++++++++++++++++--------- dlls/d3dx9_36/tests/surface.c | 43 +++++++++++----------------- 2 files changed, 57 insertions(+), 40 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index cfe6e525bff..e635d46a2b3 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -32,9 +32,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
-/* Wine-specific WIC GUIDs */ -DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47,0x3f,0xc1,0x7c,0xd3,0x22); - static const struct { const GUID *wic_guid; @@ -755,8 +752,7 @@ static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image BYTE *buffer; HRESULT hr;
- if (image->format != D3DFMT_X8R8G8B8 || (image->image_file_format != D3DXIFF_BMP - && image->image_file_format != D3DXIFF_TGA)) + if (image->format != D3DFMT_X8R8G8B8 || image->image_file_format != D3DXIFF_BMP) return FALSE;
size = image->size.width * image->size.height * 4; @@ -794,7 +790,6 @@ static const GUID *d3dx_file_format_to_wic_container_guid(D3DXIMAGE_FILEFORMAT i switch (iff) { case D3DXIFF_BMP: return &GUID_ContainerFormatBmp; - case D3DXIFF_TGA: return &GUID_WineContainerFormatTga; case D3DXIFF_JPG: return &GUID_ContainerFormatJpeg; case D3DXIFF_PNG: return &GUID_ContainerFormatPng; default: @@ -1078,12 +1073,10 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz const BOOL is_rle = !!(header->image_type & IMAGETYPE_RLE); uint32_t row_pitch, slice_pitch, i; uint8_t *img_buf = NULL, *src_row; + PALETTEENTRY *palette = NULL; const uint8_t *src_pos; HRESULT hr;
- if (image->format == D3DFMT_P8) - return E_NOTIMPL; - hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch); if (FAILED(hr)) return hr; @@ -1092,15 +1085,48 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz if (!is_rle && (src_header_size + slice_pitch) > src_data_size) return D3DXERR_INVALIDDATA;
+ if (image->format == D3DFMT_P8) + { + 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_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_format_info(D3DFMT_A8B8G8R8); + 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, 0, 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; }
/* Allocate an extra row to use as a temporary buffer. */ if (!(img_buf = malloc(slice_pitch + row_pitch))) - return E_OUTOFMEMORY; + { + hr = E_OUTOFMEMORY; + goto exit; + }
src_row = img_buf + slice_pitch; src_pos = (const uint8_t *)src_data + src_header_size; @@ -1142,10 +1168,13 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz }
image->image_buf = image->pixels = img_buf; + image->image_palette = image->palette = palette;
exit: if (img_buf && (image->image_buf != img_buf)) free(img_buf); + if (palette && (image->image_palette != palette)) + free(palette);
return hr; } @@ -1227,10 +1256,7 @@ HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3d }
/* Last resort, try TGA. */ - hr = d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); - if (hr == E_NOTIMPL) - hr = d3dx_initialize_image_from_wic(src_data, src_data_size, image, D3DXIFF_TGA, flags); - return hr; + return d3dx_initialize_image_from_tga(src_data, src_data_size, image, flags); }
switch (iff) diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 691c4011fd0..d87d68836b0 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1887,12 +1887,12 @@ static const uint8_t test_tga_grayscale_8bpp_rle_expected[] = 0x00,0x10,0x20,0x30,0x40,0x40,0x40,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0, };
-#define check_tga_surface_load(surface, expected, right_to_left, bottom_to_top, todo) \ - check_tga_surface_load_(__LINE__, surface, expected, right_to_left, bottom_to_top, todo) +#define check_tga_surface_load(surface, expected, right_to_left, bottom_to_top) \ + check_tga_surface_load_(__LINE__, surface, expected, right_to_left, bottom_to_top) static void check_tga_surface_load_(uint32_t line, IDirect3DSurface9 *surface, const uint8_t *expected, BOOL right_to_left, - BOOL bottom_to_top, BOOL todo) + BOOL bottom_to_top) { - uint32_t x, y, fmt_bpp, fmt_pitch, mismatch_count; + uint32_t x, y, fmt_bpp, fmt_pitch; D3DLOCKED_RECT lock_rect; D3DSURFACE_DESC desc; HRESULT hr; @@ -1903,7 +1903,6 @@ static void check_tga_surface_load_(uint32_t line, IDirect3DSurface9 *surface, c fmt_bpp = get_bpp_for_d3dformat(desc.Format); fmt_pitch = fmt_bpp * desc.Width; IDirect3DSurface9_LockRect(surface, &lock_rect, NULL, D3DLOCK_READONLY); - mismatch_count = 0; for (y = 0; y < desc.Height; ++y) { const uint32_t expected_row_idx = bottom_to_top ? (desc.Height - y - 1) : y; @@ -1917,11 +1916,9 @@ static void check_tga_surface_load_(uint32_t line, IDirect3DSurface9 *surface, c const uint8_t *pixel = row + (fmt_bpp * x); BOOL pixel_match = !memcmp(pixel, expected_pixel, fmt_bpp);
- if (!pixel_match) - mismatch_count++; + ok_(__FILE__, line)(pixel_match, "Pixel mismatch at (%u,%u).\n", x, y); } } - todo_wine_if(todo) ok_(__FILE__, line)(!mismatch_count, "%u mismatched pixels.\n", mismatch_count); IDirect3DSurface9_UnlockRect(surface); }
@@ -1936,8 +1933,6 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) uint32_t pixels_size;
const uint8_t *expected; - BOOL todo_hr; - BOOL todo_surface; } tga_tests[] = { { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 15, 0, 0, 4, 4, 8, 0 }, @@ -1953,22 +1948,22 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 16, 0, 0, 4, 4, 8, 0 }, test_tga_color_map_16bpp, sizeof(test_tga_color_map_16bpp), test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), - test_tga_color_map_16bpp_expected, .todo_surface = TRUE + test_tga_color_map_16bpp_expected }, { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 24, 0, 0, 4, 4, 8, 0 }, test_tga_color_map_24bpp, sizeof(test_tga_color_map_24bpp), test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), - test_tga_color_map_24bpp_expected, .todo_surface = TRUE + test_tga_color_map_24bpp_expected }, { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 256, 32, 0, 0, 4, 4, 8, 0 }, test_tga_color_map_32bpp, sizeof(test_tga_color_map_32bpp), test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), - test_tga_color_map_32bpp_expected, .todo_surface = TRUE + test_tga_color_map_32bpp_expected }, { { 0, COLORMAP_TYPE_ONE, IMAGETYPE_COLORMAPPED, 0, 128, 32, 0, 0, 4, 4, 8, 0 }, test_tga_color_map_32bpp, sizeof(test_tga_color_map_32bpp) / 2, test_tga_color_map_index_4_4, sizeof(test_tga_color_map_index_4_4), - test_tga_color_map_half_32bpp_expected, .todo_surface = TRUE + test_tga_color_map_half_32bpp_expected }, { { 0, COLORMAP_TYPE_NONE, IMAGETYPE_TRUECOLOR, 0, 0, 0, 0, 0, 4, 4, 15, 0 }, NULL, 0, @@ -2067,30 +2062,26 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device)
/* Read as default, bottom to top, left to right. */ hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].todo_hr) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE, tga_tests[i].todo_surface); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + check_tga_surface_load(surface, tga_tests[i].expected, FALSE, TRUE);
/* Read as top to bottom, left to right. */ tga->header.image_descriptor = IMAGE_TOPTOBOTTOM; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].todo_hr) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - check_tga_surface_load(surface, tga_tests[i].expected, FALSE, FALSE, tga_tests[i].todo_surface); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + check_tga_surface_load(surface, tga_tests[i].expected, FALSE, FALSE);
/* Read as bottom to top, right to left. */ tga->header.image_descriptor = IMAGE_RIGHTTOLEFT; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].color_map) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - check_tga_surface_load(surface, tga_tests[i].expected, TRUE, TRUE, FALSE); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + check_tga_surface_load(surface, tga_tests[i].expected, TRUE, TRUE);
/* Read as top to bottom, right to left. */ tga->header.image_descriptor = IMAGE_TOPTOBOTTOM | IMAGE_RIGHTTOLEFT; hr = D3DXLoadSurfaceFromFileInMemory(surface, NULL, NULL, tga, file_size, NULL, D3DX_FILTER_NONE, 0, NULL); - todo_wine_if(tga_tests[i].color_map) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - check_tga_surface_load(surface, tga_tests[i].expected, TRUE, FALSE, FALSE); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + check_tga_surface_load(surface, tga_tests[i].expected, TRUE, FALSE);
check_release((IUnknown *)surface, 0); winetest_pop_context();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=149059
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:4305: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 0000000000B500F6, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
test_tga_grayscale_8bpp_4_4
},
{ { 0, COLORMAP_TYPE_NONE, IMAGETYPE_GRAYSCALE | IMAGETYPE_RLE, 0, 0, 0, 0, 0, 4, 4, 8, 0 },
NULL, 0,
test_tga_grayscale_8bpp_4_4_rle, sizeof(test_tga_grayscale_8bpp_4_4_rle),
test_tga_grayscale_8bpp_rle_expected
},
- };
- static const uint8_t rle_test_bits[] = { 15, 16, 24, 32 };
- struct
- {
struct tga_header header;
uint8_t data[4096 * 1024];
- } *tga;
- IDirect3DSurface9 *surface;
- uint32_t i;
This could be `unsigned int` as well.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
if (tga_tests[i].color_map)
memcpy(tga->data, tga_tests[i].color_map, tga_tests[i].color_map_size);
memcpy(tga->data + tga_tests[i].color_map_size, tga_tests[i].pixels, tga_tests[i].pixels_size);
hr = D3DXGetImageInfoFromFileInMemory(tga, file_size, &info);
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
surface_fmt = (info.Format == D3DFMT_P8) ? D3DFMT_A8B8G8R8 : info.Format;
hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, info.Width, info.Height, surface_fmt, D3DPOOL_SCRATCH,
&surface, NULL);
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
/*
* Unlike D3DXGetImageInfo(), file size must be valid when loading
* image data.
*/
Maybe I'm misunderstanding the comment but, looking at the existing tests, that doesn't seem to be the case? Even in the most recent TGA tests there are a number of expected failures with `D3DXGetImageInfoFromFileInMemory()` when the data size is too small.
Orthogonally, it might be better to write it like "D3DXGetImageInfo*()" or similar, to avoid possible confusion.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
- if (image->format == D3DFMT_P8 || is_rle || bottom_to_top || right_to_left)
return E_NOTIMPL;
- 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 ((src_header_size + slice_pitch) > src_data_size)
return D3DXERR_INVALIDDATA;
- image->pixels = (uint8_t *)src_data + src_header_size;
- return D3D_OK;
+}
+static HRESULT d3dx_initialize_image_from_tga(const void *src_data, uint32_t src_data_size, struct d3dx_image *image, uint32_t flags)
Nitpick, this line is a bit on the long side (not that I mind particularly but it's kinda noticeable when the others stick to under 100-120 columns).
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
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);
No need for parentheses around `src_ptr + 1`. Only mentioning it because in the `memcpy()` right above there are none...
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
{ 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
{
memcpy(src_row, src_pos, row_pitch);
src_pos += row_pitch;
}
Can we avoid the extra copy here without making the code much of a mess?
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
{ memcpy(dst_row, src_row, row_pitch); }
src_row += row_pitch;
}
image->image_buf = image->pixels = img_buf;
return D3D_OK;
+exit:
- if (img_buf && (image->image_buf != img_buf))
free(img_buf);
We could `realloc()` the buffer here to release the memory for the temporary row, if decoding was successful.
Nice! I particularly liked the very thorough tests.