Skip to content

Webp image loader and EXT_texture_webp#2722

Open
riccardobl wants to merge 5 commits intojMonkeyEngine:masterfrom
riccardobl:webp
Open

Webp image loader and EXT_texture_webp#2722
riccardobl wants to merge 5 commits intojMonkeyEngine:masterfrom
riccardobl:webp

Conversation

@riccardobl
Copy link
Copy Markdown
Member

@riccardobl riccardobl commented Apr 25, 2026

This PR adds a Webp image loader for every platform (was only limited to android before this PR) using a java port of the rust crate image-webp's decoder.
Built on top of #2718

The PR also implements the EXT_texture_webp for the gltf loader.

Closes #2616

@riccardobl riccardobl changed the title Webp image loader Webp image loader and EXT_texture_webp Apr 25, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new image loaders based on the STB library and WebP decoder, aiming to replace older, platform-specific loaders like HDRLoader, TGALoader, and AWTLoader. It also adds support for the EXT_texture_webp glTF extension. My review highlights a critical thread-safety issue in StbImageLoader due to shared state, a potential loss of precision when loading 32-bit float HDR images, and a recommendation to improve memory efficiency by avoiding intermediate heap allocations during stream reading. Additionally, I suggest refining the exception handling in WebpImageLoader to avoid catching generic exceptions.

import com.jme3.util.BufferUtils;

public class StbImageLoader implements AssetLoader {
private final StbImage stbImage = new StbImage(BufferUtils::createByteBuffer);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The stbImage instance is shared across all calls to load(). Since AssetLoader instances are typically singletons managed by the AssetManager, and stbImage is modified via setConvertIphonePngToRgb and setUnpremultiplyOnLoad inside the load() method (lines 38-39), this creates a race condition when multiple assets are loaded concurrently. To ensure thread safety, either move the configuration to the constructor if they are constant, or instantiate StbImage locally within the load() method.

Suggested change
private final StbImage stbImage = new StbImage(BufferUtils::createByteBuffer);
@Override
public Object load(AssetInfo assetInfo) throws IOException {
StbImage stbImage = new StbImage(BufferUtils::createByteBuffer);
AssetKey<?> key = assetInfo.getKey();

Comment on lines +55 to +76
if (is16bit || isFloat) {
switch (channels) {
case 1:
jmeFormat = Image.Format.R16F;
desiredChannels = 1;
break;
case 2:
jmeFormat = Image.Format.RG16F;
desiredChannels = 2;
break;
case 3:
jmeFormat = Image.Format.RGB16F;
desiredChannels = 3;
break;
case 4:
jmeFormat = Image.Format.RGBA16F;
desiredChannels = 4;
break;
default:
throw new IOException("Unsupported number of channels: " + channels);

}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation downsamples 32-bit float images to 16-bit half-floats (Format.R16F, Format.RGB16F, etc.) regardless of whether the source is 16-bit or 32-bit float. This results in a loss of precision for HDR images that were previously supported at full 32-bit precision by HDRLoader. Consider distinguishing between is16bit and isFloat to select the appropriate 32F format when the source is a 32-bit float.

Comment on lines +50 to +52
}catch(Exception e){
throw new IOException("Failed to load WebP image", e);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Catching a generic Exception is generally discouraged as it can mask unexpected runtime issues. It is better to catch specific exceptions like IOException or RuntimeException and handle them accordingly, or let them propagate if they cannot be handled locally.

        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            throw new IOException("Failed to load WebP image", e);
        }

Comment on lines +36 to +37
byte[] data = ByteUtils.getByteContent(is);
ByteBuffer buffer = BufferUtils.createByteBuffer(data);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Reading the entire stream into a heap-allocated byte[] and then copying it into a direct ByteBuffer is memory-intensive, especially for large textures. It would be more efficient to read the stream directly into a direct ByteBuffer using a utility that avoids the intermediate heap array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebP support on desktop

1 participant