Loading images on GWT is lossy (particularly visible when using premultiplied alpha)
See original GitHub issueThis is a follow-up to #3316, which was closed, I guess partly due to lack of information. However, I did some more digging and found the root cause of the alpha banding problems in GWT. The summary is: storing pixel data in Pixmap
is lossy on GWT, and should be avoided during Texture
loading when possible.
A JSFiddle to demonstrate the issue: https://jsfiddle.net/gg9tbejf/
In my answer to the corresponding StackOverflow post, I have described a workaround. Copying here for convenience:
public class GwtTextureLoader extends AsynchronousAssetLoader<Texture, TextureLoader.TextureParameter> {
TextureData data;
Texture texture;
public GwtTextureLoader(FileHandleResolver resolver) {
super(resolver);
}
@Override
public void loadAsync(AssetManager manager, String fileName, FileHandle fileHandle, TextureLoader.TextureParameter parameter) {
if (parameter == null || parameter.textureData == null) {
Pixmap.Format format = null;
boolean genMipMaps = false;
texture = null;
if (parameter != null) {
format = parameter.format;
genMipMaps = parameter.genMipMaps;
texture = parameter.texture;
}
// Mostly these few lines changed w.r.t. TextureLoader:
GwtFileHandle gwtFileHandle = (GwtFileHandle) fileHandle;
ImageElement imageElement = gwtFileHandle.preloader.images.get(fileHandle.path());
data = new ImageTextureData(imageElement, format, genMipMaps);
} else {
data = parameter.textureData;
if (!data.isPrepared()) data.prepare();
texture = parameter.texture;
}
}
@Override
public Texture loadSync(AssetManager manager, String fileName, FileHandle fileHandle, TextureLoader.TextureParameter parameter) {
Texture texture = this.texture;
if (texture != null) {
texture.load(data);
} else {
texture = new Texture(data);
}
if (parameter != null) {
texture.setFilter(parameter.minFilter, parameter.magFilter);
texture.setWrap(parameter.wrapU, parameter.wrapV);
}
return texture;
}
@Override
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle fileHandle, TextureLoader.TextureParameter parameter) {
return null;
}
}
public class ImageTextureData implements TextureData {
private final ImageElement imageElement;
private final Pixmap.Format format;
private final boolean useMipMaps;
public ImageTextureData(ImageElement imageElement, Pixmap.Format format, boolean useMipMaps) {
this.imageElement = imageElement;
this.format = format;
this.useMipMaps = useMipMaps;
}
@Override
public TextureDataType getType() {
return TextureDataType.Custom;
}
@Override
public boolean isPrepared() {
return true;
}
@Override
public void prepare() {
}
@Override
public Pixmap consumePixmap() {
throw new GdxRuntimeException("This TextureData implementation does not use a Pixmap");
}
@Override
public boolean disposePixmap() {
throw new GdxRuntimeException("This TextureData implementation does not use a Pixmap");
}
@Override
public void consumeCustomData(int target) {
WebGLRenderingContext gl = ((GwtGL20) Gdx.gl20).gl;
gl.texImage2D(target, 0, GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, imageElement);
if (useMipMaps) {
gl.generateMipmap(target);
}
}
@Override
public int getWidth() {
return imageElement.getWidth();
}
@Override
public int getHeight() {
return imageElement.getHeight();
}
@Override
public Pixmap.Format getFormat() {
return format;
}
@Override
public boolean useMipMaps() {
return useMipMaps;
}
@Override
public boolean isManaged() {
return false;
}
}
This is likely to be more performant too, since less copying is going on. However, it does not attempt to convert images to power-of-two size (because that would of course be lossy again).
Would it make sense to replace the GWT version of TextureLoader
with something like this implementation instead? Possibly fixed up to do the lossy power-of-two conversion when needed?
Issue Analytics
- State:
- Created 8 years ago
- Comments:6 (6 by maintainers)
Top GitHub Comments
I don’t think that anybody is working on a patch, feel free to send a PR 😃
@intrigus @barkholt It looks like this is something to do with the way that Pixmap is handled by the
TextureAtlas
.I’ve created a new issue here