crashinvaders / gdx-basis-universal

KTX2/Basis Universal supercompressed GPU textures for libGDX game framework.
17 stars 2 forks source link

basis universal texture atlas loading #1

Closed jeltedeproft closed 8 months ago

jeltedeproft commented 9 months ago

how do I load a basis universal sprite sheet created gdx-texture-packer into libgdx?

metaphore commented 9 months ago

Hi, and thanks for the question. Seems like a simple guide on how to load generated atlases is missing for the GDX Texture Packer. Will fix it in the next release.

Overall, manually loading a basis-based atlas should not be any more complicated than loading a regular texture atlas. You just need to do everything that the standard TextureAtlasLoader do for you.

Before you use the code below, you should have the basisu-wrapper and basisu-gdx libraries added to your Gradle modules.

// First off, load the basis texture.
FileHandle textureFile = Gdx.files.internal("path/to/atlas/texture.basis");
TextureData textureData = new BasisuTextureData(textureFile);
Texture texture = new Texture(textureData);

// Load the atlas data.
FileHandle atlasFile = Gdx.files.internal("path/to/atlas/data.atlas");
TextureAtlas.TextureAtlasData atlasData = new TextureAtlas.TextureAtlasData(atlasFile, atlasFile.parent(), false);

// The most important part - manually assign the texture
// to all the pages before initiating the atlas object.
// BEWARE: In case your atlas has multiple pages, 
// you should assign the appropriate textures for each page.
// This example works for single-page atlases only.
for (TextureAtlas.TextureAtlasData.Page page : atlasData.getPages()) {
    page.texture = texture;
}

// Then simply instantiate the atlas object.
TextureAtlas atlas = new TextureAtlas(atlasData);

That's it. I didn't test the code, but you should get the idea.

PS: You don't need to manually dispose every atlas texture. The textures will be disposed of along with the atlas, when you call atlas.dispose()

jeltedeproft commented 9 months ago

I can't get this working, I keep getting classCastExceptions.

I have the following in my assetManager

private static void setLoaders() {
        assetManager.setLoader(TextureAtlas.class, ".basis", basisUniversalTextureAtlasLoader);
        assetManager.setLoader(Texture.class, ".basis", new BasisuTextureLoader(assetManager.getFileHandleResolver()));
        assetManager.setLoader(Texture.class, textureLoader);
        assetManager.setLoader(TextureAtlas.class, textureAtlasLoader);
}

my assetLoader has to extend a SynchronousAssetLoader (I think), so it looks like this right now (changed it multiple times)

public class BasisUniversalTextureAtlasLoader extends SynchronousAssetLoader<TextureAtlas, TextureAtlasLoader.TextureAtlasParameter> {
    public BasisUniversalTextureAtlasLoader(FileHandleResolver resolver) {
        super(resolver);
    }

    TextureAtlasData data;

    @Override
    public TextureAtlas load(AssetManager assetManager, String fileName, FileHandle file, TextureAtlasParameter parameter) {
        // First off, load the basis texture.
        FileHandle textureFile = file.parent().child(fileName + ".basis");
        TextureData textureData = new BasisuTextureData(textureFile);
        Texture texture = new Texture(textureData);

        // Load the atlas data.
        TextureAtlas.TextureAtlasData atlasData = new TextureAtlas.TextureAtlasData(file, file.parent(), false);

        // The most important part - manually assign the texture
        // to all the pages before initiating the atlas object.
        // BEWARE: In case your atlas has multiple pages,
        // you should assign the appropriate textures for each page.
        // This example works for single-page atlases only.
        for (TextureAtlas.TextureAtlasData.Page page : atlasData.getPages()) {
            page.texture = texture;
        }

        // Then simply instantiate the atlas object.
        TextureAtlas atlas = new TextureAtlas(atlasData);
        return atlas;
    }

    @Override
    public Array<AssetDescriptor> getDependencies(String fileName, FileHandle atlasFile, TextureAtlasParameter parameter) {
        Array<AssetDescriptor> dependencies = new Array();
        return dependencies;
    }

    static public class BasisuTextureAtlasParameter extends AssetLoaderParameters<TextureAtlas> {
        /** whether to flip the texture atlas vertically **/
        public boolean flip = false;

        public BasisuTextureAtlasParameter() {
        }

        public BasisuTextureAtlasParameter(boolean flip) {
            this.flip = flip;
        }
    }

}

And I get the following errors

Exception in thread "main" com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/dark.basis
    at com.badlogic.gdx.assets.AssetManager.handleTaskError(AssetManager.java:648)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:426)
    at com.badlogic.gdx.assets.AssetManager.finishLoadingAsset(AssetManager.java:483)
    at jelte.mygame.utility.AssetManagerUtility.loadAsset(AssetManagerUtility.java:150)
    at jelte.mygame.utility.AssetManagerUtility.loadTextureAtlas(AssetManagerUtility.java:118)
    at jelte.mygame.graphical.GraphicalManagerImpl.<init>(GraphicalManagerImpl.java:65)
    at jelte.mygame.StickFighter.create(StickFighter.java:39)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.initializeListener(Lwjgl3Window.java:416)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.update(Lwjgl3Window.java:366)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.loop(Lwjgl3Application.java:192)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.<init>(Lwjgl3Application.java:166)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.createApplication(Lwjgl3Launcher.java:15)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.main(Lwjgl3Launcher.java:11)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/dark.basis
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:119)
    at com.badlogic.gdx.assets.AssetLoadingTask.update(AssetLoadingTask.java:91)
    at com.badlogic.gdx.assets.AssetManager.updateTask(AssetManager.java:575)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:424)
    ... 11 more
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: java.lang.ClassCastException: class com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter cannot be cast to class com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter (com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter and com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter are in unnamed module of loader 'app')
    at com.badlogic.gdx.utils.async.AsyncResult.get(AsyncResult.java:46)
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:117)
    ... 14 more
Caused by: java.lang.ClassCastException: class com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter cannot be cast to class com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter (com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter and com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter are in unnamed module of loader 'app')
    at com.crashinvaders.basisu.gdx.BasisuTextureLoader.getDependencies(BasisuTextureLoader.java:26)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:65)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:35)
    at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:64)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
metaphore commented 9 months ago

If you're using AssetManager, you don't need to write your own loader. To make the atlas work, you just need to set up the asset manager with BasisuTextureLoader that comes with the lib.

This is the only line you need:

// Register the texture loader for the ".basis" file extension.
assetManager.setLoader(Texture.class, ".basis", new BasisuTextureLoader(assetManager.getFileHandleResolver()));

Once the asset manager knows how to load .basis textures, you're good to go.

metaphore commented 9 months ago

@jeltedeproft sorry, I made a mistake in the example code link. Please see the updated answer :arrow_up:

jeltedeproft commented 8 months ago

Sorry that I come back to this after several weeks, I put this issue aside for a while, but the solution you proposed doesn't seem to work for me.

After adding the loader class like you mentioned

    private static void setLoaders() {
        assetManager.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(filePathResolver));
        assetManager.setLoader(BitmapFont.class, ".ttf", new FreetypeFontLoader(filePathResolver));
        assetManager.setLoader(TiledMap.class, tmxMapLoader);
        assetManager.setLoader(Texture.class, textureLoader);
        assetManager.setLoader(Texture.class, ".basis", new BasisuTextureLoader(assetManager.getFileHandleResolver()));
        assetManager.setLoader(TextureAtlas.class, textureAtlasLoader);
        assetManager.setLoader(Skin.class, new FreeTypeSkinLoader(assetManager.getFileHandleResolver()));
        assetManager.setLoader(ParticleEffect.class, particleEffectLoader);
        assetManager.setLoader(Sound.class, soundLoader);
        assetManager.setLoader(Music.class, musicLoader);
        assetManager.setLoader(SoundBuffer.class, soundBufferLoader);
        loadersSet = true;
    }

i get the following error

Exception in thread "main" com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/9��;hɹ������
    at com.badlogic.gdx.assets.AssetManager.handleTaskError(AssetManager.java:648)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:426)
    at com.badlogic.gdx.assets.AssetManager.finishLoadingAsset(AssetManager.java:483)
    at jelte.mygame.utility.AssetManagerUtility.loadAsset(AssetManagerUtility.java:150)
    at jelte.mygame.utility.AssetManagerUtility.loadTextureAtlas(AssetManagerUtility.java:118)
    at jelte.mygame.graphical.GraphicalManagerImpl.<init>(GraphicalManagerImpl.java:66)
    at jelte.mygame.StickFighter.create(StickFighter.java:41)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.initializeListener(Lwjgl3Window.java:416)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.update(Lwjgl3Window.java:366)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.loop(Lwjgl3Application.java:192)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.<init>(Lwjgl3Application.java:166)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.createApplication(Lwjgl3Launcher.java:15)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.main(Lwjgl3Launcher.java:11)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/9��;hɹ������
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:119)
    at com.badlogic.gdx.assets.AssetLoadingTask.update(AssetLoadingTask.java:91)
    at com.badlogic.gdx.assets.AssetManager.updateTask(AssetManager.java:575)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:424)
    ... 11 more
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load file: sprites/9��;hɹ������
    at com.badlogic.gdx.utils.async.AsyncResult.get(AsyncResult.java:46)
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:117)
    ... 14 more
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load file: sprites/9��;hɹ������
    at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:190)
    at com.badlogic.gdx.graphics.TextureData$Factory.loadFromFile(TextureData.java:101)
    at com.badlogic.gdx.assets.loaders.TextureLoader.loadAsync(TextureLoader.java:62)
    at com.badlogic.gdx.assets.loaders.TextureLoader.loadAsync(TextureLoader.java:35)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:71)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:35)
    at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:64)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: File not found: sprites\9��;hɹ������ (Internal)
    at com.badlogic.gdx.files.FileHandle.read(FileHandle.java:142)
    at com.badlogic.gdx.files.FileHandle.readBytes(FileHandle.java:228)
    at com.badlogic.gdx.graphics.Pixmap.<init>(Pixmap.java:187)
    ... 10 more

Any ideas?

metaphore commented 8 months ago

Looking at the error, I don't think it's related to the atlas loader. There might be something wrong with the specific file, whose name appears to be in weird coding:

Couldn't load file: sprites/9��;hɹ�������

Just find the problematic file, and it should be obvious from there that it might be broken or something similar.

On a side note, unless you use your own custom asset loaders, you don't need to add them manually. Just have a look at the AssetManager`s constructor to get an idea of what is supported out of the box.

For Basis textures/atlases to work, you only need this one line:

assetManager.setLoader(Texture.class, ".basis", new BasisuTextureLoader(assetManager.getFileHandleResolver()));
jeltedeproft commented 8 months ago

Thanks for the tip! i cleaned up my code a bit with the loaders.

After some debugging I finally understand the issue.

First when the textureAtloas tries to get loaded it uses the TextureAtlasLoader to load the sprites.basis texture atlas. Nothing wrong here.

Then when it starts looking for dependencies (aka the sprites in the atlas) it got the wrong loader for me. It got the TextureLoader.

This was because in the stored loaders it had the following for the Texture key

{.basis=com.crashinvaders.basisu.gdx.BasisuTextureLoader@5e3f861,=com.badlogic.gdx.assets.loaders.TextureLoader@2fb0623e}

It then took the TextureLoader because the filename it finds in the textureAtlas was

sprites/sB

all the sprites in the basis texture atlas have a filename like this, I assume because of the way they are stored? So i think the solution is to remove the basis extension, but then every sprite sheet needs to be in basis format 🤔

Do you have any better solutions?

jeltedeproft commented 8 months ago

hmm when I remove the extension it gives me the following error

Exception in thread "main" com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/9��;hɹ������
    at com.badlogic.gdx.assets.AssetManager.handleTaskError(AssetManager.java:648)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:426)
    at com.badlogic.gdx.assets.AssetManager.finishLoadingAsset(AssetManager.java:483)
    at jelte.mygame.utility.AssetManagerUtility.loadAsset(AssetManagerUtility.java:139)
    at jelte.mygame.utility.AssetManagerUtility.loadTextureAtlas(AssetManagerUtility.java:107)
    at jelte.mygame.graphical.GraphicalManagerImpl.<init>(GraphicalManagerImpl.java:66)
    at jelte.mygame.StickFighter.create(StickFighter.java:41)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.initializeListener(Lwjgl3Window.java:416)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.update(Lwjgl3Window.java:366)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.loop(Lwjgl3Application.java:192)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.<init>(Lwjgl3Application.java:166)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.createApplication(Lwjgl3Launcher.java:15)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.main(Lwjgl3Launcher.java:11)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/9��;hɹ������
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:119)
    at com.badlogic.gdx.assets.AssetLoadingTask.update(AssetLoadingTask.java:91)
    at com.badlogic.gdx.assets.AssetManager.updateTask(AssetManager.java:575)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:424)
    ... 11 more
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: java.lang.ClassCastException: class com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter cannot be cast to class com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter (com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter and com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter are in unnamed module of loader 'app')
    at com.badlogic.gdx.utils.async.AsyncResult.get(AsyncResult.java:46)
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:117)
    ... 14 more
Caused by: java.lang.ClassCastException: class com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter cannot be cast to class com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter (com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter and com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter are in unnamed module of loader 'app')
    at com.crashinvaders.basisu.gdx.BasisuTextureLoader.getDependencies(BasisuTextureLoader.java:26)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:65)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:35)
    at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:64)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
jeltedeproft commented 8 months ago

The problem is here

image

The assetDescriptor parameters is of type

com.badlogic.gdx.assets.loaders.TextureLoader$TextureParameter@1c9cdb78

But it expects

com.crashinvaders.basisu.gdx.BasisuTextureLoader$BasisuTextureParameter

jeltedeproft commented 8 months ago

it happens here in the TextureAtlasLoader

    @Override
    public Array<AssetDescriptor> getDependencies (String fileName, FileHandle atlasFile, TextureAtlasParameter parameter) {
        FileHandle imgDir = atlasFile.parent();

        if (parameter != null)
            data = new TextureAtlasData(atlasFile, imgDir, parameter.flip);
        else {
            data = new TextureAtlasData(atlasFile, imgDir, false);
        }

        Array<AssetDescriptor> dependencies = new Array();
        for (Page page : data.getPages()) {
            TextureParameter params = new TextureParameter();
            params.format = page.format;
            params.genMipMaps = page.useMipMaps;
            params.minFilter = page.minFilter;
            params.magFilter = page.magFilter;
            dependencies.add(new AssetDescriptor(page.textureFile, Texture.class, params));
        }
        return dependencies;
    }

It creates a Textureparameter class, this is why i originally thought i had to make my own TextureAtlasLoader

metaphore commented 8 months ago

Oh, my bad. Seems like Basis texture loader for atlases was broken for a while... Thanks for the digging! I'll make a patch for the lib, but it will take some time.

Meanwhile, just use this simplified version of the loader, that is based on the standard TextureParameter type. Simply place this code to the file named CustomBasisTextureLoader.java under the com.crashinvadrs.basisu.gdx package:

package com.crashinvadrs.basisu.gdx;

import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.assets.loaders.TextureLoader;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Array;
import com.crashinvaders.basisu.gdx.BasisuGdxUtils;
import com.crashinvaders.basisu.gdx.BasisuTextureData;

public class CustomBasisTextureLoader extends AsynchronousAssetLoader<Texture, TextureLoader.TextureParameter> {

    BasisuTextureData textureData;

    public CustomBasisTextureLoader(FileHandleResolver resolver) {
        super(resolver);
        // We need to make sure this one is first time called
        // on the main thread and not during async texture loading.
        BasisuGdxUtils.initSupportedGlTextureFormats();
    }

    public void loadAsync(AssetManager manager, String fileName, FileHandle fileHandle, TextureLoader.TextureParameter parameter) {
        BasisuTextureData data;
        data = new BasisuTextureData(fileHandle);
        data.prepare();
        textureData = data;
    }

    public Texture loadSync(AssetManager manager, String fileName, FileHandle fileHandle, TextureLoader.TextureParameter parameter) {
        Texture texture = new Texture(this.textureData);
        this.textureData = null;

        if (parameter != null) {
            texture.setFilter(parameter.minFilter, parameter.magFilter);
            texture.setWrap(parameter.wrapU, parameter.wrapV);
        }

        return texture;
    }

    public Array<AssetDescriptor> getDependencies(String fileName, FileHandle fileHandle, TextureLoader.TextureParameter parameter) {
        return null;
    }
}
jeltedeproft commented 8 months ago

No problem, thanks for sticking with the issue

jeltedeproft commented 8 months ago

sorry for coming back to this agai, but I can't get it working with your modified class. I think the problem is that when the gdx-texture-packer outputs the format to basis all the files inside are renamed to gibberish. Then your code tries to use that gibberish name to find the file but doesn't find it

Here is the error I am getting

[Console output redirected to file:C:\Users\Admin\Desktop\darkOutput.txt]
Exception in thread "main" com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/9��;hɹ������
    at com.badlogic.gdx.assets.AssetManager.handleTaskError(AssetManager.java:648)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:426)
    at com.badlogic.gdx.assets.AssetManager.finishLoadingAsset(AssetManager.java:483)
    at jelte.mygame.utility.AssetManagerUtility.loadAsset(AssetManagerUtility.java:138)
    at jelte.mygame.utility.AssetManagerUtility.loadTextureAtlas(AssetManagerUtility.java:106)
    at jelte.mygame.graphical.GraphicalManagerImpl.<init>(GraphicalManagerImpl.java:66)
    at jelte.mygame.StickFighter.create(StickFighter.java:41)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.initializeListener(Lwjgl3Window.java:416)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window.update(Lwjgl3Window.java:366)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.loop(Lwjgl3Application.java:192)
    at com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application.<init>(Lwjgl3Application.java:166)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.createApplication(Lwjgl3Launcher.java:15)
    at jelte.mygame.lwjgl3.Lwjgl3Launcher.main(Lwjgl3Launcher.java:11)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: sprites/9��;hɹ������
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:119)
    at com.badlogic.gdx.assets.AssetLoadingTask.update(AssetLoadingTask.java:91)
    at com.badlogic.gdx.assets.AssetManager.updateTask(AssetManager.java:575)
    at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:424)
    ... 11 more
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: com.crashinvaders.basisu.gdx.BasisuGdxException: Couldn't load file 'sprites/9��;hɹ������'
    at com.badlogic.gdx.utils.async.AsyncResult.get(AsyncResult.java:46)
    at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:117)
    ... 14 more
Caused by: com.crashinvaders.basisu.gdx.BasisuGdxException: Couldn't load file 'sprites/9��;hɹ������'
    at com.crashinvaders.basisu.gdx.BasisuData.readFileIntoBuffer(BasisuData.java:149)
    at com.crashinvaders.basisu.gdx.BasisuData.<init>(BasisuData.java:36)
    at com.crashinvaders.basisu.gdx.BasisuTextureData.prepare(BasisuTextureData.java:148)
    at jelte.mygame.utility.CustomBasisTextureLoader.loadAsync(CustomBasisTextureLoader.java:39)
    at jelte.mygame.utility.CustomBasisTextureLoader.loadAsync(CustomBasisTextureLoader.java:1)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:71)
    at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:35)
    at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:64)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: File not found: sprites\9��;hɹ������ (Internal)
    at com.badlogic.gdx.files.FileHandle.read(FileHandle.java:142)
    at com.crashinvaders.basisu.gdx.BasisuData.readFileIntoBuffer(BasisuData.java:129)
    ... 11 more
metaphore commented 8 months ago

Hm, so the atlas page files on the file system have proper names after the texture packer export, right? Could you please also check if the names are malformed inside of the text of the .atlas file.

jeltedeproft commented 8 months ago

yeah the .atlas file has normal names This zip has the atlas in it dark.zip

metaphore commented 8 months ago

Ok, what about the actual files, do they have the same names as in the atlas file, or are they gibberish straight out of gdx-texture-packer? Or do the names get read wrong at runtime, when the atlas tries to load them? I want to understand at what point the names get broken.

If the gdx-texture-packer outputs them that way, I would ask you about the minimalistic gdx-texture-packer project so I can reproduce the issue on my end. Like get a random image or two, create an atlas for them and save the .gdxtp project file. Please send me the images and the .gdxtp file. It's important to check if that setup produces the same issue for you.

jeltedeproft commented 8 months ago

ok, so the output of the gdx-texture-packer is an atlas file with normal names, all my files have the same normal name. The dark.basis file i can't read, if I open it with notepad++ it has a bunch of weird symbols in it.

test.zip

metaphore commented 8 months ago

The gdx-texture-packer project seems totally fine and the output files are fully valid.

I tested the files in a blank project using this code:

AssetManager assetManager = new AssetManager();
assetManager.setLoader(Texture.class, ".basis", new BasisuTextureLoader(assetManager.getFileHandleResolver()));
assetManager.load("test.atlas", TextureAtlas.class);
assetManager.finishLoading();

TextureRegion region = assetManager.get("test.atlas", TextureAtlas.class).findRegion("alchemist-CLIMBING1-left", 1)

It loads atlas and yields an absolutely normal texture region that I can render on the screen.

At this point, I'd assume that the naming issue you're having is OS/system configuration related. Looks more like something is broken with text encoding. And it doesn't seems like it has anything to do with gdx-texture-packer or basis textures directly. But I wonder if you have similar issues when you change the atlas texture format to PNG? What OS are you on?

Also, it'd help a lot to understand at what stage the names get broken at runtime. If you could jump into debugging and see how the loaded TextureAtlasData looks like inside of TextureAtlasLoader#getDependencies().

jeltedeproft commented 8 months ago

I've used PNG for quite a while and it always worked normally, it was only once i switched to basis that i had this problem. I am on a Windows

Edition Windows 11 Pro Version 22H2 Installed on ‎2/‎11/‎2022 OS build 22621.2134 Experience Windows Feature Experience Pack 1000.22659.1000.0

I'll try the debugging next

metaphore commented 8 months ago

Gotcha, thanks. I will try to reproduce it on my Win10 machine.

Just to clarify, do you have the same issue with the test atlas you've sent (cannot load on runtime)?

jeltedeproft commented 8 months ago

This is the debugging output, if I look at whats inside the TextureAtlasData variable, it has an array of pagefiles and the names of those pages is gibberish

image
jeltedeproft commented 8 months ago

It also has regions and those names are also gibberish

image
jeltedeproft commented 8 months ago

omg I am a complete idiot, I'm so sorry. My atlas constant was pointing to my .basis file in stead of the atlas

Working now! thanks for all the help

metaphore commented 8 months ago

Haha, it's good it wasn't another rare system-related bug that takes an eternity to locate...

Anyway, I hope it's gonna work fine for you from here. One note, something I found myself soon after implementing the texture compression lib, Basis doesn't suit pixel art and low-res images well. There are a lot of noticeable artifacts on the compressed textures, it totally destroys the pixel art page images and produces different kinds of unexpected image distortion on different platforms (based on the transcoded format). At least when ETC1S (low-quality compression) is used. You might try UASTC (high-quality compression) which is less size-efficient but should give a more predictable and clean output.

jeltedeproft commented 8 months ago

ok, thanks for the tip, I'll use the UASTC compression and I'll do a check to see if the quality is still good.