From c854dbc58038ba88a496c2775cf5c48dc1a2a7c2 Mon Sep 17 00:00:00 2001
From: Christian Costa <titan.costa@gmail.com>
Date: Tue, 4 Nov 2014 22:41:45 +0100
Subject: wined3d: Improve DXTn support and export conversion functions for
 d3dx9_36.

---
 dlls/wined3d/dxtn.c            | 108 +++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/surface.c         |  31 ++++++++++++
 dlls/wined3d/wined3d.spec      |   8 +++
 dlls/wined3d/wined3d_private.h |  10 ----
 include/wine/wined3d.h         |  14 ++++++
 5 files changed, 161 insertions(+), 10 deletions(-)

diff --git a/dlls/wined3d/dxtn.c b/dlls/wined3d/dxtn.c
index ce98949..77f7d55 100644
--- a/dlls/wined3d/dxtn.c
+++ b/dlls/wined3d/dxtn.c
@@ -25,6 +25,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
 static void* txc_dxtn_handle;
 static void (*pfetch_2d_texel_rgba_dxt1)(int srcRowStride, const BYTE *pixData, int i, int j, DWORD *texel);
+static void (*pfetch_2d_texel_rgba_dxt3)(int srcRowStride, const BYTE *pixData, int i, int j, DWORD *texel);
+static void (*pfetch_2d_texel_rgba_dxt5)(int srcRowStride, const BYTE *pixData, int i, int j, DWORD *texel);
 static void (*ptx_compress_dxtn)(int comps, int width, int height, const BYTE *srcPixData,
                                  GLenum destformat, BYTE *dest, int dstRowStride);
 
@@ -60,6 +62,70 @@ static inline BOOL dxt1_to_x8r8g8b8(const BYTE *src, BYTE *dst, DWORD pitch_in,
     return TRUE;
 }
 
+static inline BOOL dxt3_to_x8r8g8b8(const BYTE *src, BYTE *dst, DWORD pitch_in,
+        DWORD pitch_out, unsigned int w, unsigned int h, BOOL alpha)
+{
+    unsigned int x, y;
+    DWORD color;
+
+    TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
+
+    for (y = 0; y < h; ++y)
+    {
+        DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
+        for (x = 0; x < w; ++x)
+        {
+            /* pfetch_2d_texel_rgba_dxt3 doesn't correctly handle pitch */
+            pfetch_2d_texel_rgba_dxt3(0, src + (y / 4) * pitch_in + (x / 4) * 16,
+                                      x & 3, y & 3, &color);
+            if (alpha)
+            {
+                dst_line[x] = (color & 0xff00ff00) | ((color & 0xff) << 16) |
+                              ((color & 0xff0000) >> 16);
+            }
+            else
+            {
+                dst_line[x] = 0xff000000 | ((color & 0xff) << 16) |
+                              (color & 0xff00) | ((color & 0xff0000) >> 16);
+            }
+        }
+    }
+
+    return TRUE;
+}
+
+static inline BOOL dxt5_to_x8r8g8b8(const BYTE *src, BYTE *dst, DWORD pitch_in,
+        DWORD pitch_out, unsigned int w, unsigned int h, BOOL alpha)
+{
+    unsigned int x, y;
+    DWORD color;
+
+    TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
+
+    for (y = 0; y < h; ++y)
+    {
+        DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
+        for (x = 0; x < w; ++x)
+        {
+            /* pfetch_2d_texel_rgba_dxt5 doesn't correctly handle pitch */
+            pfetch_2d_texel_rgba_dxt5(0, src + (y / 4) * pitch_in + (x / 4) * 16,
+                                      x & 3, y & 3, &color);
+            if (alpha)
+            {
+                dst_line[x] = (color & 0xff00ff00) | ((color & 0xff) << 16) |
+                              ((color & 0xff0000) >> 16);
+            }
+            else
+            {
+                dst_line[x] = 0xff000000 | ((color & 0xff) << 16) |
+                              (color & 0xff00) | ((color & 0xff0000) >> 16);
+            }
+        }
+    }
+
+    return TRUE;
+}
+
 static inline BOOL x8r8g8b8_to_dxtn(const BYTE *src, BYTE *dst, DWORD pitch_in,
         DWORD pitch_out, unsigned int w, unsigned int h, GLenum destformat, BOOL alpha)
 {
@@ -172,6 +238,46 @@ BOOL wined3d_dxt1_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch
     return FALSE;
 }
 
+BOOL wined3d_dxt3_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+        enum wined3d_format_id format, unsigned int w, unsigned int h)
+{
+    if (!txc_dxtn_handle)
+        return FALSE;
+
+    switch (format)
+    {
+        case WINED3DFMT_B8G8R8A8_UNORM:
+            return dxt3_to_x8r8g8b8(src, dst, pitch_in, pitch_out, w, h, TRUE);
+        case WINED3DFMT_B8G8R8X8_UNORM:
+            return dxt3_to_x8r8g8b8(src, dst, pitch_in, pitch_out, w, h, FALSE);
+        default:
+            break;
+    }
+
+    FIXME("Cannot find a conversion function from format DXT3 to %s.\n", debug_d3dformat(format));
+    return FALSE;
+}
+
+BOOL wined3d_dxt5_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+        enum wined3d_format_id format, unsigned int w, unsigned int h)
+{
+    if (!txc_dxtn_handle)
+        return FALSE;
+
+    switch (format)
+    {
+        case WINED3DFMT_B8G8R8A8_UNORM:
+            return dxt5_to_x8r8g8b8(src, dst, pitch_in, pitch_out, w, h, TRUE);
+        case WINED3DFMT_B8G8R8X8_UNORM:
+            return dxt5_to_x8r8g8b8(src, dst, pitch_in, pitch_out, w, h, FALSE);
+        default:
+            break;
+    }
+
+    FIXME("Cannot find a conversion function from format DXT5 to %s.\n", debug_d3dformat(format));
+    return FALSE;
+}
+
 BOOL wined3d_dxt1_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
         enum wined3d_format_id format, unsigned int w, unsigned int h)
 {
@@ -276,6 +382,8 @@ BOOL wined3d_dxtn_init(void)
         }
 
     LOAD_FUNCPTR(fetch_2d_texel_rgba_dxt1);
+    LOAD_FUNCPTR(fetch_2d_texel_rgba_dxt3);
+    LOAD_FUNCPTR(fetch_2d_texel_rgba_dxt5);
     LOAD_FUNCPTR(tx_compress_dxtn);
 
     #undef LOAD_FUNCPTR
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 140b411..0a9f68d 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -2310,6 +2310,30 @@ static void convert_dxt1_x8r8g8b8(const BYTE *src, BYTE *dst,
     wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
 }
 
+static void convert_dxt3_a8r8g8b8(const BYTE *src, BYTE *dst,
+        DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
+{
+    wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
+}
+
+static void convert_dxt3_x8r8g8b8(const BYTE *src, BYTE *dst,
+        DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
+{
+    wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
+}
+
+static void convert_dxt5_a8r8g8b8(const BYTE *src, BYTE *dst,
+        DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
+{
+    wined3d_dxt5_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
+}
+
+static void convert_dxt5_x8r8g8b8(const BYTE *src, BYTE *dst,
+        DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
+{
+    wined3d_dxt5_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
+}
+
 static void convert_a8r8g8b8_dxt1(const BYTE *src, BYTE *dst,
         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
 {
@@ -2376,8 +2400,15 @@ static const struct d3dfmt_converter_desc converters[] =
 
 static const struct d3dfmt_converter_desc dxtn_converters[] =
 {
+    /* decode DXT */
     {WINED3DFMT_DXT1,           WINED3DFMT_B8G8R8A8_UNORM,  convert_dxt1_a8r8g8b8},
     {WINED3DFMT_DXT1,           WINED3DFMT_B8G8R8X8_UNORM,  convert_dxt1_x8r8g8b8},
+    {WINED3DFMT_DXT3,           WINED3DFMT_B8G8R8A8_UNORM,  convert_dxt3_a8r8g8b8},
+    {WINED3DFMT_DXT3,           WINED3DFMT_B8G8R8X8_UNORM,  convert_dxt3_x8r8g8b8},
+    {WINED3DFMT_DXT5,           WINED3DFMT_B8G8R8A8_UNORM,  convert_dxt5_a8r8g8b8},
+    {WINED3DFMT_DXT5,           WINED3DFMT_B8G8R8X8_UNORM,  convert_dxt5_x8r8g8b8},
+
+    /* encode DXT */
     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT1,            convert_a8r8g8b8_dxt1},
     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT1,            convert_x8r8g8b8_dxt1},
     {WINED3DFMT_B5G5R5A1_UNORM, WINED3DFMT_DXT1,            convert_a1r5g5b5_dxt1},
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index c4ebd35..bb8f6f2 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -282,3 +282,11 @@
 @ cdecl wined3d_vertex_declaration_decref(ptr)
 @ cdecl wined3d_vertex_declaration_get_parent(ptr)
 @ cdecl wined3d_vertex_declaration_incref(ptr)
+
+@ cdecl wined3d_dxtn_supported()
+@ cdecl wined3d_dxt1_decode(ptr ptr long long long long long)
+@ cdecl wined3d_dxt1_encode(ptr ptr long long long long long)
+@ cdecl wined3d_dxt3_decode(ptr ptr long long long long long)
+@ cdecl wined3d_dxt3_encode(ptr ptr long long long long long)
+@ cdecl wined3d_dxt5_decode(ptr ptr long long long long long)
+@ cdecl wined3d_dxt5_encode(ptr ptr long long long long long)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index f6dd1a2..182e4d6 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3263,17 +3263,7 @@ static inline void context_apply_state(struct wined3d_context *context,
     state_table[rep].apply(context, state, rep);
 }
 
-BOOL wined3d_dxt1_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
-                         enum wined3d_format_id format, unsigned int w, unsigned int h) DECLSPEC_HIDDEN;
-BOOL wined3d_dxt1_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
-                         enum wined3d_format_id format, unsigned int w, unsigned int h) DECLSPEC_HIDDEN;
-BOOL wined3d_dxt3_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
-                         enum wined3d_format_id format, unsigned int w, unsigned int h) DECLSPEC_HIDDEN;
-BOOL wined3d_dxt5_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
-                         enum wined3d_format_id format, unsigned int w, unsigned int h) DECLSPEC_HIDDEN;
-
 BOOL wined3d_dxtn_init(void) DECLSPEC_HIDDEN;
-BOOL wined3d_dxtn_supported(void) DECLSPEC_HIDDEN;
 void wined3d_dxtn_free(void) DECLSPEC_HIDDEN;
 
 /* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index a354308..e9e4041 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2599,4 +2599,18 @@ static inline unsigned int wined3d_log2i(unsigned int x)
 #endif
 }
 
+BOOL wined3d_dxt1_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+                         enum wined3d_format_id format, unsigned int w, unsigned int h);
+BOOL wined3d_dxt1_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+                         enum wined3d_format_id format, unsigned int w, unsigned int h);
+BOOL wined3d_dxt3_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+                         enum wined3d_format_id format, unsigned int w, unsigned int h);
+BOOL wined3d_dxt3_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+                         enum wined3d_format_id format, unsigned int w, unsigned int h);
+BOOL wined3d_dxt5_decode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+                         enum wined3d_format_id format, unsigned int w, unsigned int h);
+BOOL wined3d_dxt5_encode(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
+                         enum wined3d_format_id format, unsigned int w, unsigned int h);
+BOOL wined3d_dxtn_supported(void);
+
 #endif /* __WINE_WINED3D_H */
-- 
2.6.0

