[AMSTREAM] We don't need to define WIDL_C_INLINE_WRAPPERS here anymore.
[reactos.git] / dll / directx / wine / d3dx9_36 / texture.c
index bc3daf6..d33b463 100644 (file)
@@ -180,6 +180,27 @@ HRESULT WINAPI D3DXFilterTexture(IDirect3DBaseTexture9 *texture,
     }
 }
 
+static D3DFORMAT get_luminance_replacement_format(D3DFORMAT format)
+{
+    static const struct
+    {
+        D3DFORMAT luminance_format;
+        D3DFORMAT replacement_format;
+    } luminance_replacements[] =
+    {
+        {D3DFMT_L8, D3DFMT_X8R8G8B8},
+        {D3DFMT_A8L8, D3DFMT_A8R8G8B8},
+        {D3DFMT_A4L4, D3DFMT_A4R4G4B4},
+        {D3DFMT_L16, D3DFMT_A16B16G16R16}
+    };
+    unsigned int i;
+
+    for (i = 0; i < sizeof(luminance_replacements) / sizeof(luminance_replacements[0]); ++i)
+        if (format == luminance_replacements[i].luminance_format)
+            return luminance_replacements[i].replacement_format;
+    return format;
+}
+
 HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UINT *width, UINT *height,
         UINT *miplevels, DWORD usage, D3DFORMAT *format, D3DPOOL pool)
 {
@@ -191,6 +212,7 @@ HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UIN
     D3DDISPLAYMODE mode;
     HRESULT hr;
     D3DFORMAT usedformat = D3DFMT_UNKNOWN;
+    const struct pixel_format_desc *fmt;
 
     TRACE("(%p, %p, %p, %p, %u, %p, %u)\n", device, width, height, miplevels, usage, format, pool);
 
@@ -207,73 +229,6 @@ HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UIN
     if ((pool != D3DPOOL_DEFAULT) && (pool != D3DPOOL_MANAGED) && (pool != D3DPOOL_SYSTEMMEM) && (pool != D3DPOOL_SCRATCH))
         return D3DERR_INVALIDCALL;
 
-    /* width and height */
-    if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
-        return D3DERR_INVALIDCALL;
-
-    /* 256 x 256 default width/height */
-    if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT))
-        w = h = 256;
-    else if (w == D3DX_DEFAULT)
-        w = (height ? h : 256);
-    else if (h == D3DX_DEFAULT)
-        h = (width ? w : 256);
-
-    /* ensure width/height is power of 2 */
-    if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w)))
-        w = make_pow2(w);
-
-    if (w > caps.MaxTextureWidth)
-        w = caps.MaxTextureWidth;
-
-    if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h)))
-        h = make_pow2(h);
-
-    if (h > caps.MaxTextureHeight)
-        h = caps.MaxTextureHeight;
-
-    /* texture must be square? */
-    if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
-    {
-        if (w > h)
-            h = w;
-        else
-            w = h;
-    }
-
-    if (width)
-        *width = w;
-
-    if (height)
-        *height = h;
-
-    /* miplevels */
-    if (miplevels && (usage & D3DUSAGE_AUTOGENMIPMAP))
-    {
-        if (*miplevels > 1)
-            *miplevels = 0;
-    }
-    else if (miplevels)
-    {
-        UINT max_mipmaps = 1;
-
-        if (!width && !height)
-            max_mipmaps = 9;    /* number of mipmaps in a 256x256 texture */
-        else
-        {
-            UINT max_dimen = max(w, h);
-
-            while (max_dimen > 1)
-            {
-                max_dimen >>= 1;
-                max_mipmaps++;
-            }
-        }
-
-        if (*miplevels == 0 || *miplevels > max_mipmaps)
-            *miplevels = max_mipmaps;
-    }
-
     /* format */
     if (format)
     {
@@ -299,33 +254,34 @@ HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UIN
     if ((usedformat == D3DFMT_UNKNOWN) || (usedformat == D3DX_DEFAULT))
         usedformat = D3DFMT_A8R8G8B8;
 
+    fmt = get_format_info(usedformat);
+
     hr = IDirect3D9_CheckDeviceFormat(d3d, params.AdapterOrdinal, params.DeviceType, mode.Format,
         usage, D3DRTYPE_TEXTURE, usedformat);
-
     if (FAILED(hr))
     {
-        /* Heuristic to choose the fallback format */
-        const struct pixel_format_desc *fmt = get_format_info(usedformat);
         BOOL allow_24bits;
         int bestscore = INT_MIN, i = 0, j;
         unsigned int channels;
-        const struct pixel_format_desc *curfmt;
+        const struct pixel_format_desc *curfmt, *bestfmt = NULL;
+
+        TRACE("Requested format is not supported, looking for a fallback.\n");
 
         if (!fmt)
         {
             FIXME("Pixel format %x not handled\n", usedformat);
             goto cleanup;
         }
+        fmt = get_format_info(get_luminance_replacement_format(usedformat));
 
         allow_24bits = fmt->bytes_per_pixel == 3;
-        channels = (fmt->bits[0] ? 1 : 0) + (fmt->bits[1] ? 1 : 0)
-            + (fmt->bits[2] ? 1 : 0) + (fmt->bits[3] ? 1 : 0);
+        channels = !!fmt->bits[0] + !!fmt->bits[1] + !!fmt->bits[2] + !!fmt->bits[3];
         usedformat = D3DFMT_UNKNOWN;
 
         while ((curfmt = get_format_info_idx(i)))
         {
-            unsigned int curchannels = (curfmt->bits[0] ? 1 : 0) + (curfmt->bits[1] ? 1 : 0)
-                + (curfmt->bits[2] ? 1 : 0) + (curfmt->bits[3] ? 1 : 0);
+            unsigned int curchannels = !!curfmt->bits[0] + !!curfmt->bits[1]
+                    + !!curfmt->bits[2] + !!curfmt->bits[3];
             int score;
 
             i++;
@@ -342,23 +298,96 @@ HRESULT WINAPI D3DXCheckTextureRequirements(struct IDirect3DDevice9 *device, UIN
 
             /* This format can be used, let's evaluate it.
                Weights chosen quite arbitrarily... */
-            score = 16 - 4 * (curchannels - channels);
+            score = 512 * (curfmt->type == fmt->type);
+            score -= 32 * (curchannels - channels);
 
             for (j = 0; j < 4; j++)
             {
                 int diff = curfmt->bits[j] - fmt->bits[j];
-                score += 16 - (diff < 0 ? -diff * 4 : diff);
+                score -= (diff < 0 ? -diff * 8 : diff) * (j == 0 ? 1 : 2);
             }
 
             if (score > bestscore)
             {
                 bestscore = score;
                 usedformat = curfmt->format;
+                bestfmt = curfmt;
             }
         }
+        fmt = bestfmt;
         hr = D3D_OK;
     }
 
+    if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
+        return D3DERR_INVALIDCALL;
+
+    if ((w == D3DX_DEFAULT) && (h == D3DX_DEFAULT))
+        w = h = 256;
+    else if (w == D3DX_DEFAULT)
+        w = (height ? h : 256);
+    else if (h == D3DX_DEFAULT)
+        h = (width ? w : 256);
+
+    if (fmt->block_width != 1 || fmt->block_height != 1)
+    {
+        if (w % fmt->block_width)
+            w += fmt->block_width - w % fmt->block_width;
+        if (h % fmt->block_height)
+            h += fmt->block_height - h % fmt->block_height;
+    }
+
+    if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(w)))
+        w = make_pow2(w);
+
+    if (w > caps.MaxTextureWidth)
+        w = caps.MaxTextureWidth;
+
+    if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && (!is_pow2(h)))
+        h = make_pow2(h);
+
+    if (h > caps.MaxTextureHeight)
+        h = caps.MaxTextureHeight;
+
+    if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
+    {
+        if (w > h)
+            h = w;
+        else
+            w = h;
+    }
+
+    if (width)
+        *width = w;
+
+    if (height)
+        *height = h;
+
+    if (miplevels && (usage & D3DUSAGE_AUTOGENMIPMAP))
+    {
+        if (*miplevels > 1)
+            *miplevels = 0;
+    }
+    else if (miplevels)
+    {
+        UINT max_mipmaps = 1;
+
+        if (!width && !height)
+            max_mipmaps = 9;    /* number of mipmaps in a 256x256 texture */
+        else
+        {
+            UINT max_dimen = max(w, h);
+
+            while (max_dimen > 1)
+            {
+                max_dimen >>= 1;
+                max_mipmaps++;
+            }
+        }
+
+        if (*miplevels == 0 || *miplevels > max_mipmaps)
+            *miplevels = max_mipmaps;
+    }
+
 cleanup:
 
     if (d3d)
@@ -506,6 +535,29 @@ HRESULT WINAPI D3DXCreateTexture(struct IDirect3DDevice9 *device, UINT width, UI
     return IDirect3DDevice9_CreateTexture(device, width, height, miplevels, usage, format, pool, texture, NULL);
 }
 
+static D3DFORMAT get_alpha_replacement_format(D3DFORMAT format)
+{
+    static const struct
+    {
+        D3DFORMAT orig_format;
+        D3DFORMAT replacement_format;
+    }
+    replacement_formats[] =
+    {
+        {D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8},
+        {D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5},
+        {D3DFMT_X4R4G4B4, D3DFMT_A4R4G4B4},
+        {D3DFMT_X8B8G8R8, D3DFMT_A8B8G8R8},
+        {D3DFMT_L8, D3DFMT_A8L8},
+    };
+    unsigned int i;
+
+    for (i = 0; i < sizeof(replacement_formats) / sizeof(replacement_formats[0]); ++i)
+        if (replacement_formats[i].orig_format == format)
+            return replacement_formats[i].replacement_format;
+    return format;
+}
+
 HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *device, const void *srcdata,
         UINT srcdatasize, UINT width, UINT height, UINT miplevels, DWORD usage, D3DFORMAT format,
         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
@@ -514,25 +566,26 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi
     IDirect3DTexture9 **texptr;
     IDirect3DTexture9 *buftex;
     IDirect3DSurface9 *surface;
-    BOOL file_width = FALSE, file_height = FALSE;
-    BOOL file_format = FALSE, file_miplevels = FALSE;
-    BOOL dynamic_texture;
+    BOOL dynamic_texture, format_specified = FALSE;
     D3DXIMAGE_INFO imginfo;
-    UINT loaded_miplevels;
+    UINT loaded_miplevels, skip_levels;
     D3DCAPS9 caps;
     HRESULT hr;
 
-    TRACE("(%p, %p, %u, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p)\n", device, srcdata, srcdatasize, width,
-        height, miplevels, usage, format, pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
+    TRACE("device %p, srcdata %p, srcdatasize %u, width %u, height %u, miplevels %u,"
+            " usage %#x, format %#x, pool %#x, filter %#x, mipfilter %#x, colorkey %#x,"
+            " srcinfo %p, palette %p, texture %p.\n",
+            device, srcdata, srcdatasize, width, height, miplevels, usage, format, pool,
+            filter, mipfilter, colorkey, srcinfo, palette, texture);
 
     /* check for invalid parameters */
     if (!device || !texture || !srcdata || !srcdatasize)
         return D3DERR_INVALIDCALL;
 
     hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo);
-
     if (FAILED(hr))
     {
+        FIXME("Unrecognized file format, returning failure.\n");
         *texture = NULL;
         return hr;
     }
@@ -552,52 +605,66 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi
 
     if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
         format = imginfo.Format;
+    else
+        format_specified = TRUE;
 
     if (width == D3DX_FROM_FILE)
     {
-        file_width = TRUE;
         width = imginfo.Width;
     }
 
     if (height == D3DX_FROM_FILE)
     {
-        file_height = TRUE;
         height = imginfo.Height;
     }
 
     if (format == D3DFMT_FROM_FILE)
     {
-        file_format = TRUE;
         format = imginfo.Format;
     }
 
     if (miplevels == D3DX_FROM_FILE)
     {
-        file_miplevels = TRUE;
         miplevels = imginfo.MipLevels;
     }
 
+    skip_levels = mipfilter != D3DX_DEFAULT ? mipfilter >> D3DX_SKIP_DDS_MIP_LEVELS_SHIFT : 0;
+    if (skip_levels && imginfo.MipLevels > skip_levels)
+    {
+        TRACE("Skipping the first %u (of %u) levels of a DDS mipmapped texture.\n",
+                skip_levels, imginfo.MipLevels);
+        TRACE("Texture level 0 dimensions are %ux%u.\n", imginfo.Width, imginfo.Height);
+        width >>= skip_levels;
+        height >>= skip_levels;
+        miplevels -= skip_levels;
+    }
+    else
+    {
+        skip_levels = 0;
+    }
+
     /* fix texture creation parameters */
     hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
-
     if (FAILED(hr))
     {
+        FIXME("Couldn't find suitable texture parameters.\n");
         *texture = NULL;
         return hr;
     }
 
+    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");
+        FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n");
         miplevels = imginfo.MipLevels;
     }
-
-    if (((file_width) && (width != imginfo.Width))    ||
-        ((file_height) && (height != imginfo.Height)) ||
-        ((file_format) && (format != imginfo.Format)) ||
-        ((file_miplevels) && (miplevels != imginfo.MipLevels)))
+    if (imginfo.ResourceType == D3DRTYPE_VOLUMETEXTURE
+            && D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5 && miplevels > 1)
     {
-        return D3DERR_NOTAVAILABLE;
+        FIXME("Generation of mipmaps for compressed pixel formats is not implemented yet.\n");
+        miplevels = 1;
     }
 
     if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
@@ -607,7 +674,7 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi
     dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
     if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
     {
-        hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, D3DPOOL_SYSTEMMEM, &buftex);
+        hr = D3DXCreateTexture(device, width, height, miplevels, 0, format, D3DPOOL_SYSTEMMEM, &buftex);
         texptr = &buftex;
     }
     else
@@ -618,34 +685,37 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi
 
     if (FAILED(hr))
     {
+        FIXME("Texture creation failed.\n");
         *texture = NULL;
         return hr;
     }
 
-    /* Load the file */
+    TRACE("Texture created correctly. Now loading the texture data into it.\n");
     if (imginfo.ImageFileFormat != D3DXIFF_DDS)
     {
         IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface);
         hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL);
         IDirect3DSurface9_Release(surface);
+        loaded_miplevels = min(IDirect3DTexture9_GetLevelCount(*texptr), imginfo.MipLevels);
     }
     else
     {
-        hr = load_texture_from_dds(*texptr, srcdata, palette, filter, colorkey, &imginfo);
+        hr = load_texture_from_dds(*texptr, srcdata, palette, filter, colorkey, &imginfo, skip_levels,
+                &loaded_miplevels);
     }
 
     if (FAILED(hr))
     {
+        FIXME("Texture loading failed.\n");
         IDirect3DTexture9_Release(*texptr);
         *texture = NULL;
         return hr;
     }
 
-    loaded_miplevels = min(IDirect3DTexture9_GetLevelCount(*texptr), imginfo.MipLevels);
     hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, loaded_miplevels - 1, mipfilter);
-
     if (FAILED(hr))
     {
+        FIXME("Texture filtering failed.\n");
         IDirect3DTexture9_Release(*texptr);
         *texture = NULL;
         return hr;
@@ -687,13 +757,14 @@ HRESULT WINAPI D3DXCreateTextureFromFileExW(struct IDirect3DDevice9 *device, con
         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
 {
+    void *buffer;
     HRESULT hr;
     DWORD size;
-    LPVOID buffer;
 
-    TRACE("(%p, %s, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n",
-            device, debugstr_w(srcfile), width, height, miplevels, usage, format, pool, filter,
-            mipfilter, colorkey, srcinfo, palette, texture);
+    TRACE("device %p, srcfile %s, width %u, height %u, miplevels %u, usage %#x, format %#x, "
+            "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n",
+            device, debugstr_w(srcfile), width, height, miplevels, usage, format,
+            pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
 
     if (!srcfile)
         return D3DERR_INVALIDCALL;
@@ -715,13 +786,14 @@ HRESULT WINAPI D3DXCreateTextureFromFileExA(struct IDirect3DDevice9 *device, con
         D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
         PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
 {
-    LPWSTR widename;
+    WCHAR *widename;
     HRESULT hr;
     DWORD len;
 
-    TRACE("(%p, %s, %u, %u, %u, %x, %x, %x, %u, %u, %x, %p, %p, %p): relay\n",
-            device, debugstr_a(srcfile), width, height, miplevels, usage, format, pool, filter,
-            mipfilter, colorkey, srcinfo, palette, texture);
+    TRACE("device %p, srcfile %s, width %u, height %u, miplevels %u, usage %#x, format %#x, "
+            "pool %#x, filter %#x, mipfilter %#x, colorkey 0x%08x, srcinfo %p, palette %p, texture %p.\n",
+            device, debugstr_a(srcfile), width, height, miplevels, usage, format,
+            pool, filter, mipfilter, colorkey, srcinfo, palette, texture);
 
     if (!device || !srcfile || !texture)
         return D3DERR_INVALIDCALL;
@@ -1143,7 +1215,7 @@ HRESULT WINAPI D3DXCreateVolumeTextureFromFileInMemoryEx(IDirect3DDevice9 *devic
 
     if (mip_levels > image_info.MipLevels)
     {
-        FIXME("Generation of mipmaps for volume textures is not implemented yet\n");
+        FIXME("Generation of mipmaps for volume textures is not implemented yet.\n");
         mip_levels = image_info.MipLevels;
     }
 
@@ -1301,6 +1373,12 @@ HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D f
     return D3D_OK;
 }
 
+HRESULT WINAPI D3DXFillTextureTX(struct IDirect3DTexture9 *texture, ID3DXTextureShader *texture_shader)
+{
+    FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader);
+    return E_NOTIMPL;
+}
+
 HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device,
                                                        const void *src_data,
                                                        UINT src_data_size,
@@ -1384,7 +1462,7 @@ HRESULT WINAPI D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 *device,
 
     if (mip_levels > img_info.MipLevels && (D3DFMT_DXT1 <= img_info.Format && img_info.Format <= D3DFMT_DXT5))
     {
-        FIXME("Generation of mipmaps for compressed pixel formats not supported yet\n");
+        FIXME("Generation of mipmaps for compressed pixel formats is not supported yet.\n");
         mip_levels = img_info.MipLevels;
     }
 
@@ -1670,6 +1748,12 @@ HRESULT WINAPI D3DXFillCubeTexture(struct IDirect3DCubeTexture9 *texture, LPD3DX
     return D3D_OK;
 }
 
+HRESULT WINAPI D3DXFillCubeTextureTX(struct IDirect3DCubeTexture9 *texture, ID3DXTextureShader *texture_shader)
+{
+    FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader);
+    return E_NOTIMPL;
+}
+
 HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LPD3DXFILL3D function, void *funcdata)
 {
     DWORD miplevels;
@@ -1734,6 +1818,12 @@ HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LP
     return D3D_OK;
 }
 
+HRESULT WINAPI D3DXFillVolumeTextureTX(struct IDirect3DVolumeTexture9 *texture, ID3DXTextureShader *texture_shader)
+{
+    FIXME("texture %p, texture_shader %p stub.\n", texture, texture_shader);
+    return E_NOTIMPL;
+}
+
 HRESULT WINAPI D3DXSaveTextureToFileA(const char *dst_filename, D3DXIMAGE_FILEFORMAT file_format,
         IDirect3DBaseTexture9 *src_texture, const PALETTEENTRY *src_palette)
 {
@@ -1797,10 +1887,7 @@ HRESULT WINAPI D3DXSaveTextureToFileInMemory(ID3DXBuffer **dst_buffer, D3DXIMAGE
     if (!dst_buffer || !src_texture) return D3DERR_INVALIDCALL;
 
     if (file_format == D3DXIFF_DDS)
-    {
-        FIXME("DDS file format isn't supported yet\n");
-        return E_NOTIMPL;
-    }
+        return save_dds_texture_to_memory(dst_buffer, src_texture, src_palette);
 
     type = IDirect3DBaseTexture9_GetType(src_texture);
     switch (type)