Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=24983 Signed-off-by: Matteo Bruni mbruni@codeweavers.com --- The DXTn [de]compression functions are taken pretty much unchanged from libtxc_dxtn at the time that it was merged into Mesa. It's tested code and, while certainly not the best compressor quality-wise, it is very fast, much faster than other alternatives I tested (e.g. libsquish / NVTT) and that turns out to be a critical requirement for d3dx9 in practice.
dlls/d3dx9_24/Makefile.in | 2 + dlls/d3dx9_25/Makefile.in | 2 + dlls/d3dx9_26/Makefile.in | 2 + dlls/d3dx9_27/Makefile.in | 2 + dlls/d3dx9_28/Makefile.in | 2 + dlls/d3dx9_29/Makefile.in | 2 + dlls/d3dx9_30/Makefile.in | 2 + dlls/d3dx9_31/Makefile.in | 2 + dlls/d3dx9_32/Makefile.in | 2 + dlls/d3dx9_33/Makefile.in | 2 + dlls/d3dx9_34/Makefile.in | 2 + dlls/d3dx9_35/Makefile.in | 2 + dlls/d3dx9_36/Makefile.in | 2 + dlls/d3dx9_36/d3dx9_private.h | 4 +- dlls/d3dx9_36/surface.c | 112 +++- dlls/d3dx9_36/tests/surface.c | 63 ++- dlls/d3dx9_36/tests/texture.c | 158 +++--- dlls/d3dx9_36/texture.c | 41 +- dlls/d3dx9_36/txc_compress_dxtn.c | 843 ++++++++++++++++++++++++++++++ dlls/d3dx9_36/txc_dxtn.h | 52 ++ dlls/d3dx9_36/txc_fetch_dxtn.c | 243 +++++++++ dlls/d3dx9_36/volume.c | 1 - dlls/d3dx9_37/Makefile.in | 2 + dlls/d3dx9_38/Makefile.in | 2 + dlls/d3dx9_39/Makefile.in | 2 + dlls/d3dx9_40/Makefile.in | 2 + dlls/d3dx9_41/Makefile.in | 2 + dlls/d3dx9_42/Makefile.in | 2 + dlls/d3dx9_43/Makefile.in | 2 + 29 files changed, 1425 insertions(+), 132 deletions(-) create mode 100644 dlls/d3dx9_36/txc_compress_dxtn.c create mode 100644 dlls/d3dx9_36/txc_dxtn.h create mode 100644 dlls/d3dx9_36/txc_fetch_dxtn.c
diff --git a/dlls/d3dx9_24/Makefile.in b/dlls/d3dx9_24/Makefile.in index a327292b813..faad4c49acc 100644 --- a/dlls/d3dx9_24/Makefile.in +++ b/dlls/d3dx9_24/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_25/Makefile.in b/dlls/d3dx9_25/Makefile.in index ccf37483271..292b33db2be 100644 --- a/dlls/d3dx9_25/Makefile.in +++ b/dlls/d3dx9_25/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_26/Makefile.in b/dlls/d3dx9_26/Makefile.in index 21ef9e00b2d..22bb54a4985 100644 --- a/dlls/d3dx9_26/Makefile.in +++ b/dlls/d3dx9_26/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_27/Makefile.in b/dlls/d3dx9_27/Makefile.in index 3adea191cee..4ed104a170d 100644 --- a/dlls/d3dx9_27/Makefile.in +++ b/dlls/d3dx9_27/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_28/Makefile.in b/dlls/d3dx9_28/Makefile.in index bd75a23d29f..94e059ae9d1 100644 --- a/dlls/d3dx9_28/Makefile.in +++ b/dlls/d3dx9_28/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_29/Makefile.in b/dlls/d3dx9_29/Makefile.in index 491c105ab28..94b39aee373 100644 --- a/dlls/d3dx9_29/Makefile.in +++ b/dlls/d3dx9_29/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_30/Makefile.in b/dlls/d3dx9_30/Makefile.in index 44e28b79f55..6beadbc47ea 100644 --- a/dlls/d3dx9_30/Makefile.in +++ b/dlls/d3dx9_30/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_31/Makefile.in b/dlls/d3dx9_31/Makefile.in index 0f16d27fdc2..b73f32872c3 100644 --- a/dlls/d3dx9_31/Makefile.in +++ b/dlls/d3dx9_31/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_32/Makefile.in b/dlls/d3dx9_32/Makefile.in index 99357dccea5..50bc9d0e26b 100644 --- a/dlls/d3dx9_32/Makefile.in +++ b/dlls/d3dx9_32/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_33/Makefile.in b/dlls/d3dx9_33/Makefile.in index 5a92dca61dc..7be34e1d4b0 100644 --- a/dlls/d3dx9_33/Makefile.in +++ b/dlls/d3dx9_33/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_34/Makefile.in b/dlls/d3dx9_34/Makefile.in index 84cca56ec59..248735a5311 100644 --- a/dlls/d3dx9_34/Makefile.in +++ b/dlls/d3dx9_34/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_35/Makefile.in b/dlls/d3dx9_35/Makefile.in index 640f3062044..01c809dab25 100644 --- a/dlls/d3dx9_35/Makefile.in +++ b/dlls/d3dx9_35/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_36/Makefile.in b/dlls/d3dx9_36/Makefile.in index b8a173ce01a..825e5ddfbc4 100644 --- a/dlls/d3dx9_36/Makefile.in +++ b/dlls/d3dx9_36/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 9497343f422..61ec320ba52 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -78,7 +78,7 @@ extern const struct ID3DXIncludeVtbl d3dx_include_from_file_vtbl DECLSPEC_HIDDEN static inline BOOL is_conversion_from_supported(const struct pixel_format_desc *format) { if (format->type == FORMAT_ARGB || format->type == FORMAT_ARGBF16 - || format->type == FORMAT_ARGBF) + || format->type == FORMAT_ARGBF || format->type == FORMAT_DXT) return TRUE; return !!format->to_rgba; } @@ -86,7 +86,7 @@ static inline BOOL is_conversion_from_supported(const struct pixel_format_desc * static inline BOOL is_conversion_to_supported(const struct pixel_format_desc *format) { if (format->type == FORMAT_ARGB || format->type == FORMAT_ARGBF16 - || format->type == FORMAT_ARGBF) + || format->type == FORMAT_ARGBF || format->type == FORMAT_DXT) return TRUE; return !!format->from_rgba; } diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index b78742c041c..a2eca9cbdbd 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -25,6 +25,8 @@ #include "ole2.h" #include "wincodec.h"
+#include "txc_dxtn.h" + WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); @@ -1927,6 +1929,11 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, } else /* Stretching or format conversion. */ { + const struct pixel_format_desc *dst_format; + DWORD *src_uncompressed = NULL; + unsigned int dst_pitch; + BYTE *dst_mem; + if (!is_conversion_from_supported(srcformatdesc) || !is_conversion_to_supported(destformatdesc)) { @@ -1935,10 +1942,76 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, return E_NOTIMPL; }
+ if (srcformatdesc->type == FORMAT_DXT) + { + void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, + int i, int j, void *texel); + unsigned int x, y; + + src_uncompressed = heap_alloc(src_size.width * src_size.height * sizeof(DWORD)); + if (!src_uncompressed) + { + unlock_surface(dst_surface, dst_rect, surface, FALSE); + return E_OUTOFMEMORY; + } + + switch(src_format) + { + case D3DFMT_DXT1: + fetch_dxt_texel = fetch_2d_texel_rgba_dxt1; + break; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + fetch_dxt_texel = fetch_2d_texel_rgba_dxt3; + break; + case D3DFMT_DXT4: + case D3DFMT_DXT5: + fetch_dxt_texel = fetch_2d_texel_rgba_dxt5; + break; + default: + FIXME("Unexpected compressed texture format %u.\n", src_format); + fetch_dxt_texel = NULL; + } + + TRACE("Uncompressing DXTn surface.\n"); + for (y = 0; y < src_size.height; ++y) + { + DWORD *ptr = &src_uncompressed[y * src_size.width]; + for (x = 0; x < src_size.width; ++x) + { + fetch_dxt_texel(src_pitch / sizeof(DWORD), src_memory, + x + src_rect->left, y + src_rect->top, ptr); + ++ptr; + } + } + src_memory = src_uncompressed; + src_pitch = src_size.width * sizeof(DWORD); + srcformatdesc = get_format_info(D3DFMT_A8B8G8R8); + } + + if (destformatdesc->type == FORMAT_DXT) + { + dst_mem = heap_alloc(dst_size.width * dst_size.height * sizeof(DWORD)); + if (!dst_mem) + { + heap_free(src_uncompressed); + unlock_surface(dst_surface, dst_rect, surface, FALSE); + return E_OUTOFMEMORY; + } + dst_pitch = dst_size.width * sizeof(DWORD); + dst_format = get_format_info(D3DFMT_A8B8G8R8); + } + else + { + dst_mem = lockrect.pBits; + dst_pitch = lockrect.Pitch; + dst_format = destformatdesc; + } + if ((filter & 0xf) == D3DX_FILTER_NONE) { convert_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc, - lockrect.pBits, lockrect.Pitch, 0, &dst_size, destformatdesc, color_key, src_palette); + dst_mem, dst_pitch, 0, &dst_size, dst_format, color_key, src_palette); } else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ { @@ -1948,7 +2021,42 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, /* Always apply a point filter until D3DX_FILTER_LINEAR, * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ point_filter_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc, - lockrect.pBits, lockrect.Pitch, 0, &dst_size, destformatdesc, color_key, src_palette); + dst_mem, dst_pitch, 0, &dst_size, dst_format, color_key, src_palette); + } + + heap_free(src_uncompressed); + + if (destformatdesc->type == FORMAT_DXT) + { + if (dst_rect && (dst_rect->left || dst_rect->top)) + { + FIXME("Not implemented for destination rect left / top != 0.\n"); + } + else + { + GLenum gl_format = 0; + + TRACE("Compressing DXTn surface.\n"); + switch(surfdesc.Format) + { + case D3DFMT_DXT1: + gl_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + gl_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case D3DFMT_DXT4: + case D3DFMT_DXT5: + gl_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + default: + ERR("Unexpected destination compressed format %u.\n", surfdesc.Format); + } + tx_compress_dxtn(4, dst_size.width, dst_size.height, + dst_mem, gl_format, lockrect.pBits, lockrect.Pitch); + } + heap_free(dst_mem); } }
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 11bc3159bb9..04ce57fa4f5 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -950,7 +950,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) else { PALETTEENTRY palette;
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2, D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2, + D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_4bpp(&lockrect, 0, 0, 0x57dbffff); @@ -959,7 +960,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_4bpp(&lockrect, 1, 1, 0xc8929255); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5, D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5, + D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_4bpp(&lockrect, 0, 0, 0x008cadad); @@ -968,7 +970,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_4bpp(&lockrect, 1, 1, 0xff29088c); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5, D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5, + D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_4bpp(&lockrect, 0, 0, 0xff9cdfb5); @@ -977,7 +980,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_4bpp(&lockrect, 1, 1, 0xff425d73); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16, D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16, + D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); todo_wine { @@ -988,8 +992,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_4bpp(&lockrect, 1, 1, 0xfffe9aff); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, D3DFMT_A8B8G8R8, - 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, + D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); @@ -1001,8 +1005,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
SetRect(&rect, 0, 0, 1, 1); SetRect(&destrect, 1, 1, 2, 2); - hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata_a8b8g8r8, D3DFMT_A8B8G8R8, - 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, &destrect, pixdata_a8b8g8r8, + D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_4bpp(&lockrect, 0, 0, 0xc3f04c39); @@ -1013,8 +1017,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
SetRect(&rect, 0, 0, 2, 2);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10, D3DFMT_A2R10G10B10, - 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10, + D3DFMT_A2R10G10B10, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_4bpp(&lockrect, 0, 0, 0x555c95bf); @@ -1050,7 +1054,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) ok(hr == D3D_OK, "D3DXLoadSurfaceFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK); hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x\n", hr); - ok(*(DWORD*)lockrect.pBits == 0x80f3f2f1, "Pixel color mismatch: got %#x, expected 0x80f3f2f1\n", *(DWORD*)lockrect.pBits); + ok(*(DWORD*)lockrect.pBits == 0x80f3f2f1, + "Pixel color mismatch: got %#x, expected 0x80f3f2f1\n", *(DWORD*)lockrect.pBits); hr = IDirect3DSurface9_UnlockRect(surf); ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x\n", hr); } @@ -1071,7 +1076,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2, 2, D3DFMT_A1R5G5B5, D3DPOOL_DEFAULT, &surf, NULL); if(FAILED(hr)) skip("Failed to create a surface (%#x)\n", hr); else { - hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2, D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8r3g3b2, + D3DFMT_A8R3G3B2, 4, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_2bpp(&lockrect, 0, 0, 0x6fff); @@ -1080,7 +1086,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_2bpp(&lockrect, 1, 1, 0xca4a); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5, D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a1r5g5b5, + D3DFMT_A1R5G5B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_2bpp(&lockrect, 0, 0, 0x46b5); @@ -1089,7 +1096,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_2bpp(&lockrect, 1, 1, 0x9431); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5, D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_r5g6b5, + D3DFMT_R5G6B5, 4, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_2bpp(&lockrect, 0, 0, 0xcf76); @@ -1098,7 +1106,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_2bpp(&lockrect, 1, 1, 0xa16e); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16, D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_g16r16, + D3DFMT_G16R16, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); todo_wine { @@ -1109,7 +1118,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_2bpp(&lockrect, 1, 1, 0xfe7f); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, + D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); todo_wine { @@ -1120,7 +1130,8 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_pixel_2bpp(&lockrect, 1, 1, 0xf8b8); IDirect3DSurface9_UnlockRect(surf);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10, D3DFMT_A2R10G10B10, 8, NULL, &rect, D3DX_FILTER_NONE, 0); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2r10g10b10, + D3DFMT_A2R10G10B10, 8, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#x, expected %#x\n", hr, D3D_OK); IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); check_pixel_2bpp(&lockrect, 0, 0, 0x2e57); @@ -1246,7 +1257,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) /* DXT1, DXT2, DXT3, DXT4, DXT5 */ hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surf, NULL); if (FAILED(hr)) - skip("Failed to create R8G8B8 surface, hr %#x.\n", hr); + skip("Failed to create A8R8G8B8 surface, hr %#x.\n", hr); else { hr = D3DXLoadSurfaceFromFileInMemory(surf, NULL, NULL, dds_24bit, sizeof(dds_24bit), NULL, D3DX_FILTER_NONE, 0, NULL); @@ -1260,7 +1271,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr); hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT2 format.\n"); + ok(SUCCEEDED(hr), "Failed to convert pixels to DXT2 format.\n"); check_release((IUnknown*)newsurf, 1); check_release((IUnknown*)tex, 0); } @@ -1273,7 +1284,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr); hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT3 format.\n"); + ok(SUCCEEDED(hr), "Failed to convert pixels to DXT3 format.\n"); check_release((IUnknown*)newsurf, 1); check_release((IUnknown*)tex, 0); } @@ -1286,7 +1297,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr); hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT4 format.\n"); + ok(SUCCEEDED(hr), "Failed to convert pixels to DXT4 format.\n"); check_release((IUnknown*)newsurf, 1); check_release((IUnknown*)tex, 0); } @@ -1299,11 +1310,11 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr); hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT5 format.\n"); + ok(SUCCEEDED(hr), "Failed to convert pixels to DXT5 format.\n");
SetRect(&rect, 0, 0, 4, 2); hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, &rect, surf, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); hr = D3DXLoadSurfaceFromMemory(newsurf, NULL, &rect, &dds_dxt5[128], D3DFMT_DXT5, 16, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); @@ -1332,7 +1343,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) SetRect(&rect, 2, 2, 6, 6); hr = D3DXLoadSurfaceFromMemory(newsurf, NULL, NULL, &dds_dxt5_8_8[128], D3DFMT_DXT5, 16 * 2, NULL, &rect, D3DX_FILTER_POINT, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
hr = D3DXLoadSurfaceFromMemory(newsurf, NULL, &rect, &dds_dxt5_8_8[128], D3DFMT_DXT5, 16 * 2, NULL, NULL, D3DX_FILTER_POINT, 0); @@ -1354,10 +1365,10 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); ok(SUCCEEDED(hr), "Failed to get the surface, hr %#x.\n", hr); hr = D3DXLoadSurfaceFromSurface(newsurf, NULL, NULL, surf, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels to DXT1 format.\n"); + ok(SUCCEEDED(hr), "Failed to convert pixels to DXT1 format.\n");
hr = D3DXLoadSurfaceFromSurface(surf, NULL, NULL, newsurf, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(SUCCEEDED(hr), "Failed to convert pixels from DXT1 format.\n"); + ok(SUCCEEDED(hr), "Failed to convert pixels from DXT1 format.\n");
check_release((IUnknown*)newsurf, 1); check_release((IUnknown*)tex, 0); diff --git a/dlls/d3dx9_36/tests/texture.c b/dlls/d3dx9_36/tests/texture.c index ced362ff9f1..04513fa4b07 100644 --- a/dlls/d3dx9_36/tests/texture.c +++ b/dlls/d3dx9_36/tests/texture.c @@ -636,7 +636,7 @@ static void test_D3DXCheckVolumeTextureRequirements(IDirect3DDevice9 *device) if (has_3d_dxt3) ok(format == D3DFMT_DXT3, "Returned format %u, expected %u\n", format, D3DFMT_DXT3); else - todo_wine ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8); + ok(format == D3DFMT_A8R8G8B8, "Returned format %u, expected %u\n", format, D3DFMT_A8R8G8B8);
/* mipmaps */ if (!(caps.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP)) @@ -1628,16 +1628,16 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device)
/* Check that D3DXCreateTextureFromFileInMemory accepts cube texture dds file (only first face texture is loaded) */ hr = D3DXCreateTextureFromFileInMemory(device, dds_cube_map, sizeof(dds_cube_map), &texture); - todo_wine_if (!has_2d_dxt5) - ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK); - if (SUCCEEDED(hr)) + ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK); + type = IDirect3DTexture9_GetType(texture); + ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u.\n", type, D3DRTYPE_TEXTURE); + hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); + ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#x, expected %#x.\n", hr, D3D_OK); + ok(desc.Width == 4, "Width is %u, expected 4.\n", desc.Width); + ok(desc.Height == 4, "Height is %u, expected 4.\n", desc.Height); + if (has_cube_dxt5) { - type = IDirect3DTexture9_GetType(texture); - ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u\n", type, D3DRTYPE_TEXTURE); - hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); - ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK); - ok(desc.Width == 4, "Width is %u, expected 4\n", desc.Width); - ok(desc.Height == 4, "Height is %u, expected 4\n", desc.Height); + ok(desc.Format == D3DFMT_DXT5, "Unexpected texture format %#x.\n", desc.Format); hr = IDirect3DTexture9_LockRect(texture, 0, &lock_rect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "IDirect3DTexture9_LockRect returned %#x, expected %#x\n", hr, D3D_OK); if (SUCCEEDED(hr)) @@ -1648,12 +1648,17 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device) i, ((BYTE *)lock_rect.pBits)[i], dds_cube_map[128 + i]); IDirect3DTexture9_UnlockRect(texture, 0); } - IDirect3DTexture9_Release(texture); } + else + { + ok(desc.Format == D3DFMT_A8R8G8B8, "Unexpected texture format %#x.\n", desc.Format); + skip("D3DFMT_DXT5 textures are not supported, skipping a test.\n"); + } + IDirect3DTexture9_Release(texture);
/* Test with a DXT5 texture smaller than the block size. */ hr = D3DXCreateTextureFromFileInMemory(device, dds_dxt5, sizeof(dds_dxt5), &texture); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); if (SUCCEEDED(hr) && has_2d_dxt5) { type = IDirect3DTexture9_GetType(texture); @@ -1709,7 +1714,7 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device) D3DPOOL_DEFAULT, &uncompressed_surface, NULL); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); hr = D3DXLoadSurfaceFromSurface(uncompressed_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); if (SUCCEEDED(hr)) { hr = IDirect3DSurface9_LockRect(uncompressed_surface, &lock_rect, NULL, D3DLOCK_READONLY); @@ -1739,28 +1744,25 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device) SetRect(&rect, 2, 2, 6, 6); hr = D3DXLoadSurfaceFromMemory(surface, NULL, NULL, &dds_dxt5_8_8[128], D3DFMT_DXT5, 16 * 2, NULL, &rect, D3DX_FILTER_POINT, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - if (SUCCEEDED(hr)) - { - hr = D3DXLoadSurfaceFromSurface(uncompressed_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_NONE, 0); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + hr = D3DXLoadSurfaceFromSurface(uncompressed_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
- hr = IDirect3DSurface9_LockRect(uncompressed_surface, &lock_rect, NULL, D3DLOCK_READONLY); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - for (y = 0; y < 8; ++y) + hr = IDirect3DSurface9_LockRect(uncompressed_surface, &lock_rect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + for (y = 0; y < 8; ++y) + { + for (x = 0; x < 8; ++x) { - for (x = 0; x < 8; ++x) - { - ok(compare_color(((DWORD *)lock_rect.pBits)[lock_rect.Pitch / 4 * y + x], - dds_dxt5_8_8_expected_misaligned_1[y * 8 + x], 0), - "Color at position %u, %u is 0x%08x, expected 0x%08x.\n", - x, y, ((DWORD *)lock_rect.pBits)[lock_rect.Pitch / 4 * y + x], - dds_dxt5_8_8_expected_misaligned_1[y * 8 + x]); - } + ok(compare_color(((DWORD *)lock_rect.pBits)[lock_rect.Pitch / 4 * y + x], + dds_dxt5_8_8_expected_misaligned_1[y * 8 + x], 0), + "Color at position %u, %u is 0x%08x, expected 0x%08x.\n", + x, y, ((DWORD *)lock_rect.pBits)[lock_rect.Pitch / 4 * y + x], + dds_dxt5_8_8_expected_misaligned_1[y * 8 + x]); } - hr = IDirect3DSurface9_UnlockRect(uncompressed_surface); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); } + hr = IDirect3DSurface9_UnlockRect(uncompressed_surface); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
hr = IDirect3DSurface9_LockRect(surface, &lock_rect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); @@ -1804,19 +1806,19 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device)
/* Volume textures work too. */ hr = D3DXCreateTextureFromFileInMemory(device, dds_volume_map, sizeof(dds_volume_map), &texture); - todo_wine_if (!has_2d_dxt3) - ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - type = IDirect3DTexture9_GetType(texture); - ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u.\n", type, D3DRTYPE_TEXTURE); - level_count = IDirect3DBaseTexture9_GetLevelCount((IDirect3DBaseTexture9 *)texture); - todo_wine ok(level_count == 3, "Texture has %u mip levels, 3 expected.\n", level_count); - hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); - ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#x, expected %#x.\n", hr, D3D_OK); - ok(desc.Width == 4, "Width is %u, expected 4.\n", desc.Width); - ok(desc.Height == 4, "Height is %u, expected 4.\n", desc.Height); + ok(hr == D3D_OK, "D3DXCreateTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK); + type = IDirect3DTexture9_GetType(texture); + ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u.\n", type, D3DRTYPE_TEXTURE); + level_count = IDirect3DBaseTexture9_GetLevelCount((IDirect3DBaseTexture9 *)texture); + todo_wine ok(level_count == 3, "Texture has %u mip levels, 3 expected.\n", level_count); + hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); + ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#x, expected %#x.\n", hr, D3D_OK); + ok(desc.Width == 4, "Width is %u, expected 4.\n", desc.Width); + ok(desc.Height == 4, "Height is %u, expected 4.\n", desc.Height);
+ if (has_2d_dxt3) + { + ok(desc.Format == D3DFMT_DXT3, "Unexpected texture format %#x.\n", desc.Format); hr = IDirect3DTexture9_LockRect(texture, 0, &lock_rect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "IDirect3DTexture9_LockRect returned %#x, expected %#x.\n", hr, D3D_OK); if (SUCCEEDED(hr)) @@ -1827,10 +1829,15 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device) i, ((BYTE *)lock_rect.pBits)[i], dds_volume_map[128 + i]); IDirect3DTexture9_UnlockRect(texture, 0); } - /* The lower texture levels are apparently generated by filtering the level 0 surface - * I.e. following levels from the file are ignored. */ - IDirect3DTexture9_Release(texture); } + else + { + ok(desc.Format == D3DFMT_A8R8G8B8, "Unexpected texture format %#x.\n", desc.Format); + skip("D3DFMT_DXT3 volume textures are not supported, skipping a test.\n"); + } + /* The lower texture levels are apparently generated by filtering the level 0 surface + * I.e. following levels from the file are ignored. */ + IDirect3DTexture9_Release(texture); }
static void test_D3DXCreateTextureFromFileInMemoryEx(IDirect3DDevice9 *device) @@ -1985,7 +1992,7 @@ static void test_D3DXCreateCubeTextureFromFileInMemory(IDirect3DDevice9 *device) if (SUCCEEDED(hr)) { levelcount = IDirect3DCubeTexture9_GetLevelCount(cube_texture); - todo_wine ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount); + ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount);
hr = IDirect3DCubeTexture9_GetLevelDesc(cube_texture, 0, &surface_desc); ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK); @@ -2010,8 +2017,7 @@ static void test_D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *devic
hr = D3DXCreateCubeTextureFromFileInMemoryEx(device, dds_cube_map, sizeof(dds_cube_map), D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC | D3DUSAGE_AUTOGENMIPMAP, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &cube_texture); - todo_wine_if (!has_cube_dxt5) - ok(hr == D3D_OK, "D3DXCreateCubeTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK); + ok(hr == D3D_OK, "D3DXCreateCubeTextureFromFileInMemoryEx returned %#x, expected %#x.\n", hr, D3D_OK); if (SUCCEEDED(hr)) IDirect3DCubeTexture9_Release(cube_texture); }
@@ -2036,29 +2042,25 @@ static void test_D3DXCreateVolumeTextureFromFileInMemory(IDirect3DDevice9 *devic ok(hr == D3DERR_INVALIDCALL, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
hr = D3DXCreateVolumeTextureFromFileInMemory(device, dds_volume_map, sizeof(dds_volume_map), &volume_texture); - todo_wine_if (!has_3d_dxt3) - ok(hr == D3D_OK, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x\n", hr, D3D_OK); - if (SUCCEEDED(hr)) - { - levelcount = IDirect3DVolumeTexture9_GetLevelCount(volume_texture); - ok(levelcount == 3, "GetLevelCount returned %u, expected 3\n", levelcount); - - hr = IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 0, &volume_desc); - ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK); - ok(volume_desc.Width == 4, "Got width %u, expected 4\n", volume_desc.Width); - ok(volume_desc.Height == 4, "Got height %u, expected 4\n", volume_desc.Height); - ok(volume_desc.Depth == 2, "Got depth %u, expected 2\n", volume_desc.Depth); - ok(volume_desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected D3DPOOL_MANAGED\n", volume_desc.Pool); - - hr = IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 1, &volume_desc); - ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x\n", hr, D3D_OK); - ok(volume_desc.Width == 2, "Got width %u, expected 2\n", volume_desc.Width); - ok(volume_desc.Height == 2, "Got height %u, expected 2\n", volume_desc.Height); - ok(volume_desc.Depth == 1, "Got depth %u, expected 1\n", volume_desc.Depth); - - ref = IDirect3DVolumeTexture9_Release(volume_texture); - ok(ref == 0, "Invalid reference count. Got %u, expected 0\n", ref); - } + ok(hr == D3D_OK, "D3DXCreateVolumeTextureFromFileInMemory returned %#x, expected %#x.\n", hr, D3D_OK); + levelcount = IDirect3DVolumeTexture9_GetLevelCount(volume_texture); + ok(levelcount == 3, "GetLevelCount returned %u, expected 3.\n", levelcount); + + hr = IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 0, &volume_desc); + ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x.\n", hr, D3D_OK); + ok(volume_desc.Width == 4, "Got width %u, expected 4.\n", volume_desc.Width); + ok(volume_desc.Height == 4, "Got height %u, expected 4.\n", volume_desc.Height); + ok(volume_desc.Depth == 2, "Got depth %u, expected 2.\n", volume_desc.Depth); + ok(volume_desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected D3DPOOL_MANAGED.\n", volume_desc.Pool); + + hr = IDirect3DVolumeTexture9_GetLevelDesc(volume_texture, 1, &volume_desc); + ok(hr == D3D_OK, "GetLevelDesc returned %#x, expected %#x.\n", hr, D3D_OK); + ok(volume_desc.Width == 2, "Got width %u, expected 2.\n", volume_desc.Width); + ok(volume_desc.Height == 2, "Got height %u, expected 2.\n", volume_desc.Height); + ok(volume_desc.Depth == 1, "Got depth %u, expected 1.\n", volume_desc.Depth); + + ref = IDirect3DVolumeTexture9_Release(volume_texture); + ok(ref == 0, "Invalid reference count. Got %u, expected 0.\n", ref); }
/* fills positive x face with red color */ @@ -2511,14 +2513,14 @@ START_TEST(texture) /* Check whether DXTn textures are supported. */ has_2d_dxt3 = SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3)); - hr = IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, - D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5); - has_2d_dxt5 = SUCCEEDED(hr); - hr = IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, - D3DFMT_X8R8G8B8, 0, D3DRTYPE_CUBETEXTURE, D3DFMT_DXT5); - has_cube_dxt5 = SUCCEEDED(hr); + has_2d_dxt5 = SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5)); + has_cube_dxt5 = SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, 0, D3DRTYPE_CUBETEXTURE, D3DFMT_DXT5)); has_3d_dxt3 = SUCCEEDED(IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0, D3DRTYPE_VOLUMETEXTURE, D3DFMT_DXT3)); + trace("DXTn texture support: 2D DXT3 %#x, 2D DXT5 %#x, cube DXT5 %#x, 3D dxt3 %#x.\n", + has_2d_dxt3, has_2d_dxt5, has_cube_dxt5, has_3d_dxt3);
test_D3DXCheckTextureRequirements(device); test_D3DXCheckCubeTextureRequirements(device); diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index b7d017a836f..022b32bcd8c 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -183,24 +183,30 @@ HRESULT WINAPI D3DXFilterTexture(IDirect3DBaseTexture9 *texture, } }
-static D3DFORMAT get_luminance_replacement_format(D3DFORMAT format) +static D3DFORMAT get_replacement_format(D3DFORMAT format) { static const struct { - D3DFORMAT luminance_format; + D3DFORMAT format; D3DFORMAT replacement_format; - } luminance_replacements[] = + } + replacements[] = { {D3DFMT_L8, D3DFMT_X8R8G8B8}, {D3DFMT_A8L8, D3DFMT_A8R8G8B8}, {D3DFMT_A4L4, D3DFMT_A4R4G4B4}, - {D3DFMT_L16, D3DFMT_A16B16G16R16} + {D3DFMT_L16, D3DFMT_A16B16G16R16}, + {D3DFMT_DXT1, D3DFMT_A8R8G8B8}, + {D3DFMT_DXT2, D3DFMT_A8R8G8B8}, + {D3DFMT_DXT3, D3DFMT_A8R8G8B8}, + {D3DFMT_DXT4, D3DFMT_A8R8G8B8}, + {D3DFMT_DXT5, D3DFMT_A8R8G8B8}, }; unsigned int i;
- for (i = 0; i < ARRAY_SIZE(luminance_replacements); ++i) - if (format == luminance_replacements[i].luminance_format) - return luminance_replacements[i].replacement_format; + for (i = 0; i < ARRAY_SIZE(replacements); ++i) + if (format == replacements[i].format) + return replacements[i].replacement_format; return format; }
@@ -275,7 +281,7 @@ HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UIN FIXME("Pixel format %x not handled\n", usedformat); goto cleanup; } - fmt = get_format_info(get_luminance_replacement_format(usedformat)); + fmt = get_format_info(get_replacement_format(usedformat));
allow_24bits = fmt->bytes_per_pixel == 3; channels = !!fmt->bits[0] + !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3]; @@ -564,12 +570,12 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo, PALETTEENTRY *palette, struct IDirect3DTexture9 **texture) { + BOOL dynamic_texture, format_specified = FALSE; + unsigned int loaded_miplevels, skip_levels; + IDirect3DSurface9 *surface; IDirect3DTexture9 **texptr; IDirect3DTexture9 *buftex; - IDirect3DSurface9 *surface; - BOOL dynamic_texture, format_specified = FALSE; D3DXIMAGE_INFO imginfo; - UINT loaded_miplevels, skip_levels; D3DCAPS9 caps; HRESULT hr;
@@ -656,15 +662,10 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi if (colorkey && !format_specified) format = get_alpha_replacement_format(format);
- if (imginfo.MipLevels < miplevels && (D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5)) - { - FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n"); - miplevels = imginfo.MipLevels; - } if (imginfo.ResourceType == D3DRTYPE_VOLUMETEXTURE && D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5 && miplevels > 1) { - FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n"); + FIXME("Generation of mipmaps for compressed volume textures is not implemented yet.\n"); miplevels = 1; }
@@ -1475,12 +1476,6 @@ HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device, if (FAILED(hr)) return D3DERR_INVALIDCALL;
- if (mip_levels > img_info.MipLevels && (D3DFMT_DXT1 <= img_info.Format && img_info.Format <= D3DFMT_DXT5)) - { - FIXME("Generation of mipmaps for compressed pixel formats is not supported yet.\n"); - mip_levels = img_info.MipLevels; - } - dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC); if (pool == D3DPOOL_DEFAULT && !dynamic_texture) { diff --git a/dlls/d3dx9_36/txc_compress_dxtn.c b/dlls/d3dx9_36/txc_compress_dxtn.c new file mode 100644 index 00000000000..9534f5bc60b --- /dev/null +++ b/dlls/d3dx9_36/txc_compress_dxtn.c @@ -0,0 +1,843 @@ +/* + * libtxc_dxtn + * Version: 1.0 + * + * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include "txc_dxtn.h" + +/* weights used for error function, basically weights (unsquared 2/4/1) according to rgb->luminance conversion + not sure if this really reflects visual perception */ +#define REDWEIGHT 4 +#define GREENWEIGHT 16 +#define BLUEWEIGHT 1 + +#define ALPHACUT 127 + +static void fancybasecolorsearch( GLubyte *blkaddr, GLubyte srccolors[4][4][4], GLubyte *bestcolor[2], + GLint numxpixels, GLint numypixels, GLint type, GLboolean haveAlpha) +{ + /* use same luminance-weighted distance metric to determine encoding as for finding the base colors */ + + /* TODO could also try to find a better encoding for the 3-color-encoding type, this really should be done + if it's rgba_dxt1 and we have alpha in the block, currently even values which will be mapped to black + due to their alpha value will influence the result */ + GLint i, j, colors, z; + GLuint pixerror, pixerrorred, pixerrorgreen, pixerrorblue, pixerrorbest; + GLint colordist, blockerrlin[2][3]; + GLubyte nrcolor[2]; + GLint pixerrorcolorbest[3]; + GLubyte enc = 0; + GLubyte cv[4][4]; + GLubyte testcolor[2][3]; + +/* fprintf(stderr, "color begin 0 r/g/b %d/%d/%d, 1 r/g/b %d/%d/%d\n", + bestcolor[0][0], bestcolor[0][1], bestcolor[0][2], bestcolor[1][0], bestcolor[1][1], bestcolor[1][2]);*/ + if (((bestcolor[0][0] & 0xf8) << 8 | (bestcolor[0][1] & 0xfc) << 3 | bestcolor[0][2] >> 3) < + ((bestcolor[1][0] & 0xf8) << 8 | (bestcolor[1][1] & 0xfc) << 3 | bestcolor[1][2] >> 3)) { + testcolor[0][0] = bestcolor[0][0]; + testcolor[0][1] = bestcolor[0][1]; + testcolor[0][2] = bestcolor[0][2]; + testcolor[1][0] = bestcolor[1][0]; + testcolor[1][1] = bestcolor[1][1]; + testcolor[1][2] = bestcolor[1][2]; + } + else { + testcolor[1][0] = bestcolor[0][0]; + testcolor[1][1] = bestcolor[0][1]; + testcolor[1][2] = bestcolor[0][2]; + testcolor[0][0] = bestcolor[1][0]; + testcolor[0][1] = bestcolor[1][1]; + testcolor[0][2] = bestcolor[1][2]; + } + + for (i = 0; i < 3; i ++) { + cv[0][i] = testcolor[0][i]; + cv[1][i] = testcolor[1][i]; + cv[2][i] = (testcolor[0][i] * 2 + testcolor[1][i]) / 3; + cv[3][i] = (testcolor[0][i] + testcolor[1][i] * 2) / 3; + } + + blockerrlin[0][0] = 0; + blockerrlin[0][1] = 0; + blockerrlin[0][2] = 0; + blockerrlin[1][0] = 0; + blockerrlin[1][1] = 0; + blockerrlin[1][2] = 0; + + nrcolor[0] = 0; + nrcolor[1] = 0; + + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + pixerrorbest = 0xffffffff; + for (colors = 0; colors < 4; colors++) { + colordist = srccolors[j][i][0] - (cv[colors][0]); + pixerror = colordist * colordist * REDWEIGHT; + pixerrorred = colordist; + colordist = srccolors[j][i][1] - (cv[colors][1]); + pixerror += colordist * colordist * GREENWEIGHT; + pixerrorgreen = colordist; + colordist = srccolors[j][i][2] - (cv[colors][2]); + pixerror += colordist * colordist * BLUEWEIGHT; + pixerrorblue = colordist; + if (pixerror < pixerrorbest) { + enc = colors; + pixerrorbest = pixerror; + pixerrorcolorbest[0] = pixerrorred; + pixerrorcolorbest[1] = pixerrorgreen; + pixerrorcolorbest[2] = pixerrorblue; + } + } + if (enc == 0) { + for (z = 0; z < 3; z++) { + blockerrlin[0][z] += 3 * pixerrorcolorbest[z]; + } + nrcolor[0] += 3; + } + else if (enc == 2) { + for (z = 0; z < 3; z++) { + blockerrlin[0][z] += 2 * pixerrorcolorbest[z]; + } + nrcolor[0] += 2; + for (z = 0; z < 3; z++) { + blockerrlin[1][z] += 1 * pixerrorcolorbest[z]; + } + nrcolor[1] += 1; + } + else if (enc == 3) { + for (z = 0; z < 3; z++) { + blockerrlin[0][z] += 1 * pixerrorcolorbest[z]; + } + nrcolor[0] += 1; + for (z = 0; z < 3; z++) { + blockerrlin[1][z] += 2 * pixerrorcolorbest[z]; + } + nrcolor[1] += 2; + } + else if (enc == 1) { + for (z = 0; z < 3; z++) { + blockerrlin[1][z] += 3 * pixerrorcolorbest[z]; + } + nrcolor[1] += 3; + } + } + } + if (nrcolor[0] == 0) nrcolor[0] = 1; + if (nrcolor[1] == 0) nrcolor[1] = 1; + for (j = 0; j < 2; j++) { + for (i = 0; i < 3; i++) { + GLint newvalue = testcolor[j][i] + blockerrlin[j][i] / nrcolor[j]; + if (newvalue <= 0) + testcolor[j][i] = 0; + else if (newvalue >= 255) + testcolor[j][i] = 255; + else testcolor[j][i] = newvalue; + } + } + + if ((abs(testcolor[0][0] - testcolor[1][0]) < 8) && + (abs(testcolor[0][1] - testcolor[1][1]) < 4) && + (abs(testcolor[0][2] - testcolor[1][2]) < 8)) { + /* both colors are so close they might get encoded as the same 16bit values */ + GLubyte coldiffred, coldiffgreen, coldiffblue, coldiffmax, factor, ind0, ind1; + + coldiffred = abs(testcolor[0][0] - testcolor[1][0]); + coldiffgreen = 2 * abs(testcolor[0][1] - testcolor[1][1]); + coldiffblue = abs(testcolor[0][2] - testcolor[1][2]); + coldiffmax = coldiffred; + if (coldiffmax < coldiffgreen) coldiffmax = coldiffgreen; + if (coldiffmax < coldiffblue) coldiffmax = coldiffblue; + if (coldiffmax > 0) { + if (coldiffmax > 4) factor = 2; + else if (coldiffmax > 2) factor = 3; + else factor = 4; + /* Won't do much if the color value is near 255... */ + /* argh so many ifs */ + if (testcolor[1][1] >= testcolor[0][1]) { + ind1 = 1; ind0 = 0; + } + else { + ind1 = 0; ind0 = 1; + } + if ((testcolor[ind1][1] + factor * coldiffgreen) <= 255) + testcolor[ind1][1] += factor * coldiffgreen; + else testcolor[ind1][1] = 255; + if ((testcolor[ind1][0] - testcolor[ind0][1]) > 0) { + if ((testcolor[ind1][0] + factor * coldiffred) <= 255) + testcolor[ind1][0] += factor * coldiffred; + else testcolor[ind1][0] = 255; + } + else { + if ((testcolor[ind0][0] + factor * coldiffred) <= 255) + testcolor[ind0][0] += factor * coldiffred; + else testcolor[ind0][0] = 255; + } + if ((testcolor[ind1][2] - testcolor[ind0][2]) > 0) { + if ((testcolor[ind1][2] + factor * coldiffblue) <= 255) + testcolor[ind1][2] += factor * coldiffblue; + else testcolor[ind1][2] = 255; + } + else { + if ((testcolor[ind0][2] + factor * coldiffblue) <= 255) + testcolor[ind0][2] += factor * coldiffblue; + else testcolor[ind0][2] = 255; + } + } + } + + if (((testcolor[0][0] & 0xf8) << 8 | (testcolor[0][1] & 0xfc) << 3 | testcolor[0][2] >> 3) < + ((testcolor[1][0] & 0xf8) << 8 | (testcolor[1][1] & 0xfc) << 3 | testcolor[1][2]) >> 3) { + for (i = 0; i < 3; i++) { + bestcolor[0][i] = testcolor[0][i]; + bestcolor[1][i] = testcolor[1][i]; + } + } + else { + for (i = 0; i < 3; i++) { + bestcolor[0][i] = testcolor[1][i]; + bestcolor[1][i] = testcolor[0][i]; + } + } + +/* fprintf(stderr, "color end 0 r/g/b %d/%d/%d, 1 r/g/b %d/%d/%d\n", + bestcolor[0][0], bestcolor[0][1], bestcolor[0][2], bestcolor[1][0], bestcolor[1][1], bestcolor[1][2]);*/ +} + + + +static void storedxtencodedblock( GLubyte *blkaddr, GLubyte srccolors[4][4][4], GLubyte *bestcolor[2], + GLint numxpixels, GLint numypixels, GLuint type, GLboolean haveAlpha) +{ + /* use same luminance-weighted distance metric to determine encoding as for finding the base colors */ + + GLint i, j, colors; + GLuint testerror, testerror2, pixerror, pixerrorbest; + GLint colordist; + GLushort color0, color1, tempcolor; + GLuint bits = 0, bits2 = 0; + GLubyte *colorptr; + GLubyte enc = 0; + GLubyte cv[4][4]; + + bestcolor[0][0] = bestcolor[0][0] & 0xf8; + bestcolor[0][1] = bestcolor[0][1] & 0xfc; + bestcolor[0][2] = bestcolor[0][2] & 0xf8; + bestcolor[1][0] = bestcolor[1][0] & 0xf8; + bestcolor[1][1] = bestcolor[1][1] & 0xfc; + bestcolor[1][2] = bestcolor[1][2] & 0xf8; + + color0 = bestcolor[0][0] << 8 | bestcolor[0][1] << 3 | bestcolor[0][2] >> 3; + color1 = bestcolor[1][0] << 8 | bestcolor[1][1] << 3 | bestcolor[1][2] >> 3; + if (color0 < color1) { + tempcolor = color0; color0 = color1; color1 = tempcolor; + colorptr = bestcolor[0]; bestcolor[0] = bestcolor[1]; bestcolor[1] = colorptr; + } + + + for (i = 0; i < 3; i++) { + cv[0][i] = bestcolor[0][i]; + cv[1][i] = bestcolor[1][i]; + cv[2][i] = (bestcolor[0][i] * 2 + bestcolor[1][i]) / 3; + cv[3][i] = (bestcolor[0][i] + bestcolor[1][i] * 2) / 3; + } + + testerror = 0; + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + pixerrorbest = 0xffffffff; + for (colors = 0; colors < 4; colors++) { + colordist = srccolors[j][i][0] - cv[colors][0]; + pixerror = colordist * colordist * REDWEIGHT; + colordist = srccolors[j][i][1] - cv[colors][1]; + pixerror += colordist * colordist * GREENWEIGHT; + colordist = srccolors[j][i][2] - cv[colors][2]; + pixerror += colordist * colordist * BLUEWEIGHT; + if (pixerror < pixerrorbest) { + pixerrorbest = pixerror; + enc = colors; + } + } + testerror += pixerrorbest; + bits |= enc << (2 * (j * 4 + i)); + } + } + /* some hw might disagree but actually decoding should always use 4-color encoding + for non-dxt1 formats */ + if (type == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || type == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { + for (i = 0; i < 3; i++) { + cv[2][i] = (bestcolor[0][i] + bestcolor[1][i]) / 2; + /* this isn't used. Looks like the black color constant can only be used + with RGB_DXT1 if I read the spec correctly (note though that the radeon gpu disagrees, + it will decode 3 to black even with DXT3/5), and due to how the color searching works + it won't get used even then */ + cv[3][i] = 0; + } + testerror2 = 0; + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + pixerrorbest = 0xffffffff; + if ((type == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) && (srccolors[j][i][3] <= ALPHACUT)) { + enc = 3; + pixerrorbest = 0; /* don't calculate error */ + } + else { + /* we're calculating the same what we have done already for colors 0-1 above... */ + for (colors = 0; colors < 3; colors++) { + colordist = srccolors[j][i][0] - cv[colors][0]; + pixerror = colordist * colordist * REDWEIGHT; + colordist = srccolors[j][i][1] - cv[colors][1]; + pixerror += colordist * colordist * GREENWEIGHT; + colordist = srccolors[j][i][2] - cv[colors][2]; + pixerror += colordist * colordist * BLUEWEIGHT; + if (pixerror < pixerrorbest) { + pixerrorbest = pixerror; + /* need to exchange colors later */ + if (colors > 1) enc = colors; + else enc = colors ^ 1; + } + } + } + testerror2 += pixerrorbest; + bits2 |= enc << (2 * (j * 4 + i)); + } + } + } else { + testerror2 = 0xffffffff; + } + + /* finally we're finished, write back colors and bits */ + if ((testerror > testerror2) || (haveAlpha)) { + *blkaddr++ = color1 & 0xff; + *blkaddr++ = color1 >> 8; + *blkaddr++ = color0 & 0xff; + *blkaddr++ = color0 >> 8; + *blkaddr++ = bits2 & 0xff; + *blkaddr++ = ( bits2 >> 8) & 0xff; + *blkaddr++ = ( bits2 >> 16) & 0xff; + *blkaddr = bits2 >> 24; + } + else { + *blkaddr++ = color0 & 0xff; + *blkaddr++ = color0 >> 8; + *blkaddr++ = color1 & 0xff; + *blkaddr++ = color1 >> 8; + *blkaddr++ = bits & 0xff; + *blkaddr++ = ( bits >> 8) & 0xff; + *blkaddr++ = ( bits >> 16) & 0xff; + *blkaddr = bits >> 24; + } +} + +static void encodedxtcolorblockfaster( GLubyte *blkaddr, GLubyte srccolors[4][4][4], + GLint numxpixels, GLint numypixels, GLuint type ) +{ +/* simplistic approach. We need two base colors, simply use the "highest" and the "lowest" color + present in the picture as base colors */ + + /* define lowest and highest color as shortest and longest vector to 0/0/0, though the + vectors are weighted similar to their importance in rgb-luminance conversion + doesn't work too well though... + This seems to be a rather difficult problem */ + + GLubyte *bestcolor[2]; + GLubyte basecolors[2][3]; + GLubyte i, j; + GLuint lowcv, highcv, testcv; + GLboolean haveAlpha = GL_FALSE; + + lowcv = highcv = srccolors[0][0][0] * srccolors[0][0][0] * REDWEIGHT + + srccolors[0][0][1] * srccolors[0][0][1] * GREENWEIGHT + + srccolors[0][0][2] * srccolors[0][0][2] * BLUEWEIGHT; + bestcolor[0] = bestcolor[1] = srccolors[0][0]; + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* don't use this as a base color if the pixel will get black/transparent anyway */ + if ((type != GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || (srccolors[j][i][3] > ALPHACUT)) { + testcv = srccolors[j][i][0] * srccolors[j][i][0] * REDWEIGHT + + srccolors[j][i][1] * srccolors[j][i][1] * GREENWEIGHT + + srccolors[j][i][2] * srccolors[j][i][2] * BLUEWEIGHT; + if (testcv > highcv) { + highcv = testcv; + bestcolor[1] = srccolors[j][i]; + } + else if (testcv < lowcv) { + lowcv = testcv; + bestcolor[0] = srccolors[j][i]; + } + } + else haveAlpha = GL_TRUE; + } + } + /* make sure the original color values won't get touched... */ + for (j = 0; j < 2; j++) { + for (i = 0; i < 3; i++) { + basecolors[j][i] = bestcolor[j][i]; + } + } + bestcolor[0] = basecolors[0]; + bestcolor[1] = basecolors[1]; + + /* try to find better base colors */ + fancybasecolorsearch(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha); + /* find the best encoding for these colors, and store the result */ + storedxtencodedblock(blkaddr, srccolors, bestcolor, numxpixels, numypixels, type, haveAlpha); +} + +static void writedxt5encodedalphablock( GLubyte *blkaddr, GLubyte alphabase1, GLubyte alphabase2, + GLubyte alphaenc[16]) +{ + *blkaddr++ = alphabase1; + *blkaddr++ = alphabase2; + *blkaddr++ = alphaenc[0] | (alphaenc[1] << 3) | ((alphaenc[2] & 3) << 6); + *blkaddr++ = (alphaenc[2] >> 2) | (alphaenc[3] << 1) | (alphaenc[4] << 4) | ((alphaenc[5] & 1) << 7); + *blkaddr++ = (alphaenc[5] >> 1) | (alphaenc[6] << 2) | (alphaenc[7] << 5); + *blkaddr++ = alphaenc[8] | (alphaenc[9] << 3) | ((alphaenc[10] & 3) << 6); + *blkaddr++ = (alphaenc[10] >> 2) | (alphaenc[11] << 1) | (alphaenc[12] << 4) | ((alphaenc[13] & 1) << 7); + *blkaddr++ = (alphaenc[13] >> 1) | (alphaenc[14] << 2) | (alphaenc[15] << 5); +} + +static void encodedxt5alpha(GLubyte *blkaddr, GLubyte srccolors[4][4][4], + GLint numxpixels, GLint numypixels) +{ + GLubyte alphabase[2], alphause[2]; + GLshort alphatest[2]; + GLuint alphablockerror1, alphablockerror2, alphablockerror3; + GLubyte i, j, aindex, acutValues[7]; + GLubyte alphaenc1[16], alphaenc2[16], alphaenc3[16]; + GLboolean alphaabsmin = GL_FALSE; + GLboolean alphaabsmax = GL_FALSE; + GLshort alphadist; + + /* find lowest and highest alpha value in block, alphabase[0] lowest, alphabase[1] highest */ + alphabase[0] = 0xff; alphabase[1] = 0x0; + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if (srccolors[j][i][3] == 0) + alphaabsmin = GL_TRUE; + else if (srccolors[j][i][3] == 255) + alphaabsmax = GL_TRUE; + else { + if (srccolors[j][i][3] > alphabase[1]) + alphabase[1] = srccolors[j][i][3]; + if (srccolors[j][i][3] < alphabase[0]) + alphabase[0] = srccolors[j][i][3]; + } + } + } + + + if ((alphabase[0] > alphabase[1]) && !(alphaabsmin && alphaabsmax)) { /* one color, either max or min */ + /* shortcut here since it is a very common case (and also avoids later problems) */ + /* || (alphabase[0] == alphabase[1] && !alphaabsmin && !alphaabsmax) */ + /* could also thest for alpha0 == alpha1 (and not min/max), but probably not common, so don't bother */ + + *blkaddr++ = srccolors[0][0][3]; + blkaddr++; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; + *blkaddr++ = 0; +/* fprintf(stderr, "enc0 used\n");*/ + return; + } + + /* find best encoding for alpha0 > alpha1 */ + /* it's possible this encoding is better even if both alphaabsmin and alphaabsmax are true */ + alphablockerror1 = 0x0; + alphablockerror2 = 0xffffffff; + alphablockerror3 = 0xffffffff; + if (alphaabsmin) alphause[0] = 0; + else alphause[0] = alphabase[0]; + if (alphaabsmax) alphause[1] = 255; + else alphause[1] = alphabase[1]; + /* calculate the 7 cut values, just the middle between 2 of the computed alpha values */ + for (aindex = 0; aindex < 7; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphause[0] * (2*aindex + 1) + alphause[1] * (14 - (2*aindex + 1))) / 14; + } + + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i][3] > acutValues[0]) { + alphaenc1[4*j + i] = 0; + alphadist = srccolors[j][i][3] - alphause[1]; + } + else if (srccolors[j][i][3] > acutValues[1]) { + alphaenc1[4*j + i] = 2; + alphadist = srccolors[j][i][3] - (alphause[1] * 6 + alphause[0] * 1) / 7; + } + else if (srccolors[j][i][3] > acutValues[2]) { + alphaenc1[4*j + i] = 3; + alphadist = srccolors[j][i][3] - (alphause[1] * 5 + alphause[0] * 2) / 7; + } + else if (srccolors[j][i][3] > acutValues[3]) { + alphaenc1[4*j + i] = 4; + alphadist = srccolors[j][i][3] - (alphause[1] * 4 + alphause[0] * 3) / 7; + } + else if (srccolors[j][i][3] > acutValues[4]) { + alphaenc1[4*j + i] = 5; + alphadist = srccolors[j][i][3] - (alphause[1] * 3 + alphause[0] * 4) / 7; + } + else if (srccolors[j][i][3] > acutValues[5]) { + alphaenc1[4*j + i] = 6; + alphadist = srccolors[j][i][3] - (alphause[1] * 2 + alphause[0] * 5) / 7; + } + else if (srccolors[j][i][3] > acutValues[6]) { + alphaenc1[4*j + i] = 7; + alphadist = srccolors[j][i][3] - (alphause[1] * 1 + alphause[0] * 6) / 7; + } + else { + alphaenc1[4*j + i] = 1; + alphadist = srccolors[j][i][3] - alphause[0]; + } + alphablockerror1 += alphadist * alphadist; + } + } +/* for (i = 0; i < 16; i++) { + fprintf(stderr, "%d ", alphaenc1[i]); + } + fprintf(stderr, "cutVals "); + for (i = 0; i < 8; i++) { + fprintf(stderr, "%d ", acutValues[i]); + } + fprintf(stderr, "srcVals "); + for (j = 0; j < numypixels; j++) + for (i = 0; i < numxpixels; i++) { + fprintf(stderr, "%d ", srccolors[j][i][3]); + } + + fprintf(stderr, "\n"); + }*/ + /* it's not very likely this encoding is better if both alphaabsmin and alphaabsmax + are false but try it anyway */ + if (alphablockerror1 >= 32) { + + /* don't bother if encoding is already very good, this condition should also imply + we have valid alphabase colors which we absolutely need (alphabase[0] <= alphabase[1]) */ + alphablockerror2 = 0; + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphabase[0] * (10 - (2*aindex + 1)) + alphabase[1] * (2*aindex + 1)) / 10; + } + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i][3] == 0) { + alphaenc2[4*j + i] = 6; + alphadist = 0; + } + else if (srccolors[j][i][3] == 255) { + alphaenc2[4*j + i] = 7; + alphadist = 0; + } + else if (srccolors[j][i][3] <= acutValues[0]) { + alphaenc2[4*j + i] = 0; + alphadist = srccolors[j][i][3] - alphabase[0]; + } + else if (srccolors[j][i][3] <= acutValues[1]) { + alphaenc2[4*j + i] = 2; + alphadist = srccolors[j][i][3] - (alphabase[0] * 4 + alphabase[1] * 1) / 5; + } + else if (srccolors[j][i][3] <= acutValues[2]) { + alphaenc2[4*j + i] = 3; + alphadist = srccolors[j][i][3] - (alphabase[0] * 3 + alphabase[1] * 2) / 5; + } + else if (srccolors[j][i][3] <= acutValues[3]) { + alphaenc2[4*j + i] = 4; + alphadist = srccolors[j][i][3] - (alphabase[0] * 2 + alphabase[1] * 3) / 5; + } + else if (srccolors[j][i][3] <= acutValues[4]) { + alphaenc2[4*j + i] = 5; + alphadist = srccolors[j][i][3] - (alphabase[0] * 1 + alphabase[1] * 4) / 5; + } + else { + alphaenc2[4*j + i] = 1; + alphadist = srccolors[j][i][3] - alphabase[1]; + } + alphablockerror2 += alphadist * alphadist; + } + } + + + /* skip this if the error is already very small + this encoding is MUCH better on average than #2 though, but expensive! */ + if ((alphablockerror2 > 96) && (alphablockerror1 > 96)) { + GLshort blockerrlin1 = 0; + GLshort blockerrlin2 = 0; + GLubyte nralphainrangelow = 0; + GLubyte nralphainrangehigh = 0; + alphatest[0] = 0xff; + alphatest[1] = 0x0; + /* if we have large range it's likely there are values close to 0/255, try to map them to 0/255 */ + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if ((srccolors[j][i][3] > alphatest[1]) && (srccolors[j][i][3] < (255 -(alphabase[1] - alphabase[0]) / 28))) + alphatest[1] = srccolors[j][i][3]; + if ((srccolors[j][i][3] < alphatest[0]) && (srccolors[j][i][3] > (alphabase[1] - alphabase[0]) / 28)) + alphatest[0] = srccolors[j][i][3]; + } + } + /* shouldn't happen too often, don't really care about those degenerated cases */ + if (alphatest[1] <= alphatest[0]) { + alphatest[0] = 1; + alphatest[1] = 254; +/* fprintf(stderr, "only 1 or 0 colors for encoding!\n");*/ + } + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; + } + + /* find the "average" difference between the alpha values and the next encoded value. + This is then used to calculate new base values. + Should there be some weighting, i.e. those values closer to alphatest[x] have more weight, + since they will see more improvement, and also because the values in the middle are somewhat + likely to get no improvement at all (because the base values might move in different directions)? + OTOH it would mean the values in the middle are even less likely to get an improvement + */ + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + if (srccolors[j][i][3] <= alphatest[0] / 2) { + } + else if (srccolors[j][i][3] > ((255 + alphatest[1]) / 2)) { + } + else if (srccolors[j][i][3] <= acutValues[0]) { + blockerrlin1 += (srccolors[j][i][3] - alphatest[0]); + nralphainrangelow += 1; + } + else if (srccolors[j][i][3] <= acutValues[1]) { + blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); + blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i][3] <= acutValues[2]) { + blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); + blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i][3] <= acutValues[3]) { + blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); + blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else if (srccolors[j][i][3] <= acutValues[4]) { + blockerrlin1 += (srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); + blockerrlin2 += (srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5); + nralphainrangelow += 1; + nralphainrangehigh += 1; + } + else { + blockerrlin2 += (srccolors[j][i][3] - alphatest[1]); + nralphainrangehigh += 1; + } + } + } + /* shouldn't happen often, needed to avoid div by zero */ + if (nralphainrangelow == 0) nralphainrangelow = 1; + if (nralphainrangehigh == 0) nralphainrangehigh = 1; + alphatest[0] = alphatest[0] + (blockerrlin1 / nralphainrangelow); +/* fprintf(stderr, "block err lin low %d, nr %d\n", blockerrlin1, nralphainrangelow); + fprintf(stderr, "block err lin high %d, nr %d\n", blockerrlin2, nralphainrangehigh);*/ + /* again shouldn't really happen often... */ + if (alphatest[0] < 0) { + alphatest[0] = 0; +/* fprintf(stderr, "adj alpha base val to 0\n");*/ + } + alphatest[1] = alphatest[1] + (blockerrlin2 / nralphainrangehigh); + if (alphatest[1] > 255) { + alphatest[1] = 255; +/* fprintf(stderr, "adj alpha base val to 255\n");*/ + } + + alphablockerror3 = 0; + for (aindex = 0; aindex < 5; aindex++) { + /* don't forget here is always rounded down */ + acutValues[aindex] = (alphatest[0] * (10 - (2*aindex + 1)) + alphatest[1] * (2*aindex + 1)) / 10; + } + for (j = 0; j < numypixels; j++) { + for (i = 0; i < numxpixels; i++) { + /* maybe it's overkill to have the most complicated calculation just for the error + calculation which we only need to figure out if encoding1 or encoding2 is better... */ + if (srccolors[j][i][3] <= alphatest[0] / 2) { + alphaenc3[4*j + i] = 6; + alphadist = srccolors[j][i][3]; + } + else if (srccolors[j][i][3] > ((255 + alphatest[1]) / 2)) { + alphaenc3[4*j + i] = 7; + alphadist = 255 - srccolors[j][i][3]; + } + else if (srccolors[j][i][3] <= acutValues[0]) { + alphaenc3[4*j + i] = 0; + alphadist = srccolors[j][i][3] - alphatest[0]; + } + else if (srccolors[j][i][3] <= acutValues[1]) { + alphaenc3[4*j + i] = 2; + alphadist = srccolors[j][i][3] - (alphatest[0] * 4 + alphatest[1] * 1) / 5; + } + else if (srccolors[j][i][3] <= acutValues[2]) { + alphaenc3[4*j + i] = 3; + alphadist = srccolors[j][i][3] - (alphatest[0] * 3 + alphatest[1] * 2) / 5; + } + else if (srccolors[j][i][3] <= acutValues[3]) { + alphaenc3[4*j + i] = 4; + alphadist = srccolors[j][i][3] - (alphatest[0] * 2 + alphatest[1] * 3) / 5; + } + else if (srccolors[j][i][3] <= acutValues[4]) { + alphaenc3[4*j + i] = 5; + alphadist = srccolors[j][i][3] - (alphatest[0] * 1 + alphatest[1] * 4) / 5; + } + else { + alphaenc3[4*j + i] = 1; + alphadist = srccolors[j][i][3] - alphatest[1]; + } + alphablockerror3 += alphadist * alphadist; + } + } + } + } + /* write the alpha values and encoding back. */ + if ((alphablockerror1 <= alphablockerror2) && (alphablockerror1 <= alphablockerror3)) { +/* if (alphablockerror1 > 96) fprintf(stderr, "enc1 used, error %d\n", alphablockerror1);*/ + writedxt5encodedalphablock( blkaddr, alphause[1], alphause[0], alphaenc1 ); + } + else if (alphablockerror2 <= alphablockerror3) { +/* if (alphablockerror2 > 96) fprintf(stderr, "enc2 used, error %d\n", alphablockerror2);*/ + writedxt5encodedalphablock( blkaddr, alphabase[0], alphabase[1], alphaenc2 ); + } + else { +/* fprintf(stderr, "enc3 used, error %d\n", alphablockerror3);*/ + writedxt5encodedalphablock( blkaddr, (GLubyte)alphatest[0], (GLubyte)alphatest[1], alphaenc3 ); + } +} + +static void extractsrccolors( GLubyte srcpixels[4][4][4], const GLchan *srcaddr, + GLint srcRowStride, GLint numxpixels, GLint numypixels, GLint comps) +{ + GLubyte i, j, c; + const GLchan *curaddr; + for (j = 0; j < numypixels; j++) { + curaddr = srcaddr + j * srcRowStride * comps; + for (i = 0; i < numxpixels; i++) { + for (c = 0; c < comps; c++) { + srcpixels[j][i][c] = *curaddr++ / (CHAN_MAX / 255); + } + } + } +} + + +void tx_compress_dxtn(GLint srccomps, GLint width, GLint height, const GLubyte *srcPixData, + GLenum destFormat, GLubyte *dest, GLint dstRowStride) +{ + GLubyte *blkaddr = dest; + GLubyte srcpixels[4][4][4]; + const GLchan *srcaddr = srcPixData; + GLint numxpixels, numypixels; + GLint i, j; + GLint dstRowDiff; + + switch (destFormat) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + /* hmm we used to get called without dstRowStride... */ + dstRowDiff = dstRowStride >= (width * 2) ? dstRowStride - (((width + 3) & ~3) * 2) : 0; +/* fprintf(stderr, "dxt1 tex width %d tex height %d dstRowStride %d\n", + width, height, dstRowStride); */ + for (j = 0; j < height; j += 4) { + if (height > j + 3) numypixels = 4; + else numypixels = height - j; + srcaddr = srcPixData + j * width * srccomps; + for (i = 0; i < width; i += 4) { + if (width > i + 3) numxpixels = 4; + else numxpixels = width - i; + extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); + encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat); + srcaddr += srccomps * numxpixels; + blkaddr += 8; + } + blkaddr += dstRowDiff; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0; +/* fprintf(stderr, "dxt3 tex width %d tex height %d dstRowStride %d\n", + width, height, dstRowStride); */ + for (j = 0; j < height; j += 4) { + if (height > j + 3) numypixels = 4; + else numypixels = height - j; + srcaddr = srcPixData + j * width * srccomps; + for (i = 0; i < width; i += 4) { + if (width > i + 3) numxpixels = 4; + else numxpixels = width - i; + extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); + *blkaddr++ = (srcpixels[0][0][3] >> 4) | (srcpixels[0][1][3] & 0xf0); + *blkaddr++ = (srcpixels[0][2][3] >> 4) | (srcpixels[0][3][3] & 0xf0); + *blkaddr++ = (srcpixels[1][0][3] >> 4) | (srcpixels[1][1][3] & 0xf0); + *blkaddr++ = (srcpixels[1][2][3] >> 4) | (srcpixels[1][3][3] & 0xf0); + *blkaddr++ = (srcpixels[2][0][3] >> 4) | (srcpixels[2][1][3] & 0xf0); + *blkaddr++ = (srcpixels[2][2][3] >> 4) | (srcpixels[2][3][3] & 0xf0); + *blkaddr++ = (srcpixels[3][0][3] >> 4) | (srcpixels[3][1][3] & 0xf0); + *blkaddr++ = (srcpixels[3][2][3] >> 4) | (srcpixels[3][3][3] & 0xf0); + encodedxtcolorblockfaster(blkaddr, srcpixels, numxpixels, numypixels, destFormat); + srcaddr += srccomps * numxpixels; + blkaddr += 8; + } + blkaddr += dstRowDiff; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + dstRowDiff = dstRowStride >= (width * 4) ? dstRowStride - (((width + 3) & ~3) * 4) : 0; +/* fprintf(stderr, "dxt5 tex width %d tex height %d dstRowStride %d\n", + width, height, dstRowStride); */ + for (j = 0; j < height; j += 4) { + if (height > j + 3) numypixels = 4; + else numypixels = height - j; + srcaddr = srcPixData + j * width * srccomps; + for (i = 0; i < width; i += 4) { + if (width > i + 3) numxpixels = 4; + else numxpixels = width - i; + extractsrccolors(srcpixels, srcaddr, width, numxpixels, numypixels, srccomps); + encodedxt5alpha(blkaddr, srcpixels, numxpixels, numypixels); + encodedxtcolorblockfaster(blkaddr + 8, srcpixels, numxpixels, numypixels, destFormat); + srcaddr += srccomps * numxpixels; + blkaddr += 16; + } + blkaddr += dstRowDiff; + } + break; + default: + /* fprintf(stderr, "libdxtn: Bad dstFormat %d in tx_compress_dxtn\n", destFormat); */ + return; + } +} + + diff --git a/dlls/d3dx9_36/txc_dxtn.h b/dlls/d3dx9_36/txc_dxtn.h new file mode 100644 index 00000000000..3c1e3d46c28 --- /dev/null +++ b/dlls/d3dx9_36/txc_dxtn.h @@ -0,0 +1,52 @@ +/* + * libtxc_dxtn + * Version: 1.0 + * + * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _TXC_DXTN_H +#define _TXC_DXTN_H + +#include "winternl.h" +#include "wine/wgl.h" + +typedef GLubyte GLchan; +#define UBYTE_TO_CHAN(b) (b) +#define CHAN_MAX 255 +#define RCOMP 0 +#define GCOMP 1 +#define BCOMP 2 +#define ACOMP 3 + +void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel); +void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel); +void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel); +void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel); + +void tx_compress_dxtn(GLint srccomps, GLint width, GLint height, + const GLubyte *srcPixData, GLenum destformat, + GLubyte *dest, GLint dstRowStride); + +#endif /* _TXC_DXTN_H */ diff --git a/dlls/d3dx9_36/txc_fetch_dxtn.c b/dlls/d3dx9_36/txc_fetch_dxtn.c new file mode 100644 index 00000000000..7f0db56a155 --- /dev/null +++ b/dlls/d3dx9_36/txc_fetch_dxtn.c @@ -0,0 +1,243 @@ +/* + * libtxc_dxtn + * Version: 1.0 + * + * Copyright (C) 2004 Roland Scheidegger All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include "txc_dxtn.h" + +#define EXP5TO8R(packedcol) \ + ((((packedcol) >> 8) & 0xf8) | (((packedcol) >> 13) & 0x7)) + +#define EXP6TO8G(packedcol) \ + ((((packedcol) >> 3) & 0xfc) | (((packedcol) >> 9) & 0x3)) + +#define EXP5TO8B(packedcol) \ + ((((packedcol) << 3) & 0xf8) | (((packedcol) >> 2) & 0x7)) + +#define EXP4TO8(col) \ + ((col) | ((col) << 4)) + +/* inefficient. To be efficient, it would be necessary to decode 16 pixels at once */ + +static void dxt135_decode_imageblock ( const GLubyte *img_block_src, + GLint i, GLint j, GLuint dxt_type, GLvoid *texel ) { + GLchan *rgba = (GLchan *) texel; + const GLushort color0 = img_block_src[0] | (img_block_src[1] << 8); + const GLushort color1 = img_block_src[2] | (img_block_src[3] << 8); + const GLuint bits = img_block_src[4] | (img_block_src[5] << 8) | + (img_block_src[6] << 16) | (img_block_src[7] << 24); + /* What about big/little endian? */ + GLubyte bit_pos = 2 * (j * 4 + i) ; + GLubyte code = (GLubyte) ((bits >> bit_pos) & 3); + + rgba[ACOMP] = CHAN_MAX; + switch (code) { + case 0: + rgba[RCOMP] = UBYTE_TO_CHAN( EXP5TO8R(color0) ); + rgba[GCOMP] = UBYTE_TO_CHAN( EXP6TO8G(color0) ); + rgba[BCOMP] = UBYTE_TO_CHAN( EXP5TO8B(color0) ); + break; + case 1: + rgba[RCOMP] = UBYTE_TO_CHAN( EXP5TO8R(color1) ); + rgba[GCOMP] = UBYTE_TO_CHAN( EXP6TO8G(color1) ); + rgba[BCOMP] = UBYTE_TO_CHAN( EXP5TO8B(color1) ); + break; + case 2: + if ((dxt_type > 1) || (color0 > color1)) { + rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) * 2 + EXP5TO8R(color1)) / 3) ); + rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) * 2 + EXP6TO8G(color1)) / 3) ); + rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) * 2 + EXP5TO8B(color1)) / 3) ); + } + else { + rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) + EXP5TO8R(color1)) / 2) ); + rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) + EXP6TO8G(color1)) / 2) ); + rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) + EXP5TO8B(color1)) / 2) ); + } + break; + case 3: + if ((dxt_type > 1) || (color0 > color1)) { + rgba[RCOMP] = UBYTE_TO_CHAN( ((EXP5TO8R(color0) + EXP5TO8R(color1) * 2) / 3) ); + rgba[GCOMP] = UBYTE_TO_CHAN( ((EXP6TO8G(color0) + EXP6TO8G(color1) * 2) / 3) ); + rgba[BCOMP] = UBYTE_TO_CHAN( ((EXP5TO8B(color0) + EXP5TO8B(color1) * 2) / 3) ); + } + else { + rgba[RCOMP] = 0; + rgba[GCOMP] = 0; + rgba[BCOMP] = 0; + if (dxt_type == 1) rgba[ACOMP] = UBYTE_TO_CHAN(0); + } + break; + default: + /* CANNOT happen (I hope) */ + break; + } +} + + +void fetch_2d_texel_rgb_dxt1(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel) +{ + /* Extract the (i,j) pixel from pixdata and return it + * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. + */ + + const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8); + dxt135_decode_imageblock(blksrc, (i&3), (j&3), 0, texel); +} + + +void fetch_2d_texel_rgba_dxt1(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel) +{ + /* Extract the (i,j) pixel from pixdata and return it + * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. + */ + + const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 8); + dxt135_decode_imageblock(blksrc, (i&3), (j&3), 1, texel); +} + +void fetch_2d_texel_rgba_dxt3(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel) { + + /* Extract the (i,j) pixel from pixdata and return it + * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. + */ + + GLchan *rgba = (GLchan *) texel; + const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 16); +#if 0 + /* Simple 32bit version. */ +/* that's pretty brain-dead for a single pixel, isn't it? */ + const GLubyte bit_pos = 4 * ((j&3) * 4 + (i&3)); + const GLuint alpha_low = blksrc[0] | (blksrc[1] << 8) | (blksrc[2] << 16) | (blksrc[3] << 24); + const GLuint alpha_high = blksrc[4] | (blksrc[5] << 8) | (blksrc[6] << 16) | (blksrc[7] << 24); + + dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel); + if (bit_pos < 32) + rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8((alpha_low >> bit_pos) & 15)) ); + else + rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8((alpha_high >> (bit_pos - 32)) & 15)) ); +#endif +#if 1 +/* TODO test this! */ + const GLubyte anibble = (blksrc[((j&3) * 4 + (i&3)) / 2] >> (4 * (i&1))) & 0xf; + dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel); + rgba[ACOMP] = UBYTE_TO_CHAN( (GLubyte)(EXP4TO8(anibble)) ); +#endif + +} + +void fetch_2d_texel_rgba_dxt5(GLint srcRowStride, const GLubyte *pixdata, + GLint i, GLint j, GLvoid *texel) { + + /* Extract the (i,j) pixel from pixdata and return it + * in texel[RCOMP], texel[GCOMP], texel[BCOMP], texel[ACOMP]. + */ + + GLchan *rgba = (GLchan *) texel; + const GLubyte *blksrc = (pixdata + ((srcRowStride + 3) / 4 * (j / 4) + (i / 4)) * 16); + const GLubyte alpha0 = blksrc[0]; + const GLubyte alpha1 = blksrc[1]; +#if 0 + const GLubyte bit_pos = 3 * ((j&3) * 4 + (i&3)); + /* simple 32bit version */ + const GLuint bits_low = blksrc[2] | (blksrc[3] << 8) | (blksrc[4] << 16) | (blksrc[5] << 24); + const GLuint bits_high = blksrc[6] | (blksrc[7] << 8); + GLubyte code; + + if (bit_pos < 30) + code = (GLubyte) ((bits_low >> bit_pos) & 7); + else if (bit_pos == 30) + code = (GLubyte) ((bits_low >> 30) & 3) | ((bits_high << 2) & 4); + else + code = (GLubyte) ((bits_high >> (bit_pos - 32)) & 7); +#endif +#if 1 +/* TODO test this! */ + const GLubyte bit_pos = ((j&3) * 4 + (i&3)) * 3; + const GLubyte acodelow = blksrc[2 + bit_pos / 8]; + const GLubyte acodehigh = blksrc[3 + bit_pos / 8]; + const GLubyte code = (acodelow >> (bit_pos & 0x7) | + (acodehigh << (8 - (bit_pos & 0x7)))) & 0x7; +#endif + dxt135_decode_imageblock(blksrc + 8, (i&3), (j&3), 2, texel); +#if 0 + if (alpha0 > alpha1) { + switch (code) { + case 0: + rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 ); + break; + case 1: + rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 ); + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7) ); + break; + } + } + else { + switch (code) { + case 0: + rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 ); + break; + case 1: + rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 ); + break; + case 2: + case 3: + case 4: + case 5: + rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5) ); + break; + case 6: + rgba[ACOMP] = 0; + break; + case 7: + rgba[ACOMP] = CHAN_MAX; + break; + } + } +#endif +/* not sure. Which version is faster? */ +#if 1 +/* TODO test this */ + if (code == 0) + rgba[ACOMP] = UBYTE_TO_CHAN( alpha0 ); + else if (code == 1) + rgba[ACOMP] = UBYTE_TO_CHAN( alpha1 ); + else if (alpha0 > alpha1) + rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (8 - code) + (alpha1 * (code - 1))) / 7) ); + else if (code < 6) + rgba[ACOMP] = UBYTE_TO_CHAN( ((alpha0 * (6 - code) + (alpha1 * (code - 1))) / 5) ); + else if (code == 6) + rgba[ACOMP] = 0; + else + rgba[ACOMP] = CHAN_MAX; +#endif +} diff --git a/dlls/d3dx9_36/volume.c b/dlls/d3dx9_36/volume.c index 32ff030618c..93afaa16b10 100644 --- a/dlls/d3dx9_36/volume.c +++ b/dlls/d3dx9_36/volume.c @@ -185,7 +185,6 @@ HRESULT WINAPI D3DXLoadVolumeFromMemory(IDirect3DVolume9 *dst_volume, { const BYTE *src_addr;
- if (!is_conversion_from_supported(src_format_desc) || !is_conversion_to_supported(dst_format_desc)) { diff --git a/dlls/d3dx9_37/Makefile.in b/dlls/d3dx9_37/Makefile.in index d16a0ce05aa..a0896df82ed 100644 --- a/dlls/d3dx9_37/Makefile.in +++ b/dlls/d3dx9_37/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_38/Makefile.in b/dlls/d3dx9_38/Makefile.in index 4a02ab4174e..24bbc3f0cf5 100644 --- a/dlls/d3dx9_38/Makefile.in +++ b/dlls/d3dx9_38/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_39/Makefile.in b/dlls/d3dx9_39/Makefile.in index 5a3840574aa..a3f7626f33f 100644 --- a/dlls/d3dx9_39/Makefile.in +++ b/dlls/d3dx9_39/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_40/Makefile.in b/dlls/d3dx9_40/Makefile.in index 581e18dba11..fbbcb0c04eb 100644 --- a/dlls/d3dx9_40/Makefile.in +++ b/dlls/d3dx9_40/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_41/Makefile.in b/dlls/d3dx9_41/Makefile.in index 63a0be753ff..9b44213117b 100644 --- a/dlls/d3dx9_41/Makefile.in +++ b/dlls/d3dx9_41/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_42/Makefile.in b/dlls/d3dx9_42/Makefile.in index ff391a20253..f725e87471f 100644 --- a/dlls/d3dx9_42/Makefile.in +++ b/dlls/d3dx9_42/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c diff --git a/dlls/d3dx9_43/Makefile.in b/dlls/d3dx9_43/Makefile.in index e009a41c57a..dbebc51ad07 100644 --- a/dlls/d3dx9_43/Makefile.in +++ b/dlls/d3dx9_43/Makefile.in @@ -22,6 +22,8 @@ C_SRCS = \ sprite.c \ surface.c \ texture.c \ + txc_compress_dxtn.c \ + txc_fetch_dxtn.c \ util.c \ volume.c \ xfile.c