Add .webp support - #5167
Conversation
There was a problem hiding this comment.
Pull request overview
Adds WebP image decoding support to the MTA client texture pipeline so .webp files (and in-memory WebP byte buffers) can be used with dxCreateTexture and related paths.
Changes:
- Vendors and builds a decoder-only subset of
libwebpand wires it into the Windows/x86 client build. - Extends
CPixelsManagerto detect WebP, read its dimensions, and decode it into PLAIN pixels. - Uploads decoded WebP pixels into a D3D texture when D3DX cannot decode the source format.
Note for commit hygiene (to help future maintainers): please ensure the final commit message(s) include the motivation for adding WebP, what scenarios were tested (e.g., the attached resource), and any relevant build/upgrade steps (e.g., running install_libwebp).
Reviewed changes
Copilot reviewed 9 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| win-create-projects.bat | Adds install_libwebp step to the Windows project generation workflow. |
| vendor/libwebp/README.md | Adds vendored library readme/scaffold documentation. |
| vendor/libwebp/premake5.lua | Defines a decoder-only static library build for libwebp (Windows/x86 scoped). |
| vendor/libwebp/.gitignore | Ignores extracted vendor contents while keeping scaffolding files tracked. |
| utils/buildactions/install_libwebp.lua | Adds an auto-download/install action for libwebp with hash verification. |
| premake5.lua | Requires the new install action and includes the vendor/libwebp project in the workspace. |
| Client/sdk/core/CPixelsManagerInterface.h | Extends pixel format enum to include WEBP. |
| Client/core/premake5.lua | Adds libwebp include paths and links libwebp into the Client Core. |
| Client/core/Graphics/CRenderItem.FileTexture.cpp | Adds a WebP decode+manual upload path for file- and memory-backed textures. |
| Client/core/Graphics/CPixelsManager.cpp | Adds WebP detection, size queries, and decode-to-PLAIN conversion. |
| Client/core/CFileFormatWebP.cpp | Implements WebP magic detection, dimension parsing, and BGRA decode helpers. |
| Client/core/CFileFormat.h | Exposes the WebP helper function declarations. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 12 changed files in this pull request and generated no new comments.
Suppressed comments (5)
utils/buildactions/install_libwebp.lua:100
- This prompt uses "(Y/n)" but empty input is treated as "no". Consider changing it to "(y/N)" to match the behavior.
io.write("Update `install_libwebp.lua` file? (Y/n) ")
local input = io.read():lower()
if (input == "y" or input == "yes") then
update_install_libwebp("LIBWEBP", LIBWEBP_VERSION, downloaded_hash)
Client/core/Graphics/CRenderItem.FileTexture.cpp:144
- The .webp fast-path bypasses the usual D3DXCreate*FromFileEx flow, so requested sizing (uiSizeX/uiSizeY) and the requested texture format (the
formatparameter) are ignored. This means .webp textures are always created at their native decoded size in A8R8G8B8, which is a behavioral difference vs PNG/JPG where size/format are honored.
// D3DX cannot decode every format we support, so we need to perform the following steps:
// Load the file, ask CPixelsManager what it is, and if it's not something D3DX can handle, convert to PLAIN and upload manually
if (strFilename.EndsWithI(".webp"))
{
std::vector<char> fileBytes;
Client/core/Graphics/CRenderItem.FileTexture.cpp:260
- In the in-memory pixels path, the WEBP branch uploads decoded pixels as a new A8R8G8B8 texture and returns early, so the
formatargument is ignored for WEBP buffers. If callers request a different render/texture format, behavior will differ from the D3DXCreateTextureFromFileInMemoryEx path.
else if (inFormat == EPixelsFormat::WEBP) // any format that D3DX cannot decode itself
{
CPixels plainPixels;
if (!pPixelsManager->ChangePixelsFormat(*pPixels, plainPixels, EPixelsFormat::PLAIN))
return;
utils/buildactions/install_libwebp.lua:145
- When reinstalling/upgrading, the extracted libwebp sources are copied into vendor/libwebp/ without first removing previously extracted directories. This can leave stale files behind across upgrades (e.g., files removed upstream), which can cause confusing build issues.
-- Move all files from _extract/libwebp*/* to vendor/libwebp/
os.expanddir_wildcard(extract_dir .. "libwebp*", LIBWEBP_PATH)
-- Clean up scratch folder
os.rmdir(extract_dir)
utils/buildactions/install_libwebp.lua:67
- The prompt says "(Y/n)", but the code aborts unless the user explicitly types "y"/"yes". Either accept empty input as "yes" or change the prompt to reflect that the default is "no".
This issue also appears on line 97 of the same file.
io.write(("Does version '%s' look OK to you? (Y/n) "):format(meta["tag_name"]))
local input = io.read():lower()
if not (input == "y" or input == "yes") then
errormsg("Aborting due to user request.")
return false
Summary
This PR adds support for the WebP image format to the MTA client's texture pipeline. Scripts can now pass
.webpfiles (and in-memory WebP byte buffers) todxCreateTexture, and they will be decoded and uploaded just like PNG/JPG.Motivation
WebP typically produces 25–35% smaller files than PNG at equivalent visual quality, with full alpha-channel support. For resources with a lot of images, this can reduce download size without sacrificing quality. It's also quickly becoming the default for web-based applications, which means we can use the same images for our website as well as our MTA server in-game.
Test plan
I have attached a small test resource that displays two .webp images, one using
dxCreateTextureand one usingdxDrawImagedirectly with the file path. The two images are drawn one over another, to showcase the transparancy working for the second image.webp.zip
Checklist