EsotericSoftware / spine-runtimes

2D skeletal animation runtimes for Spine.
http://esotericsoftware.com/
Other
4.43k stars 2.92k forks source link

[spine-pixi] I need to load SkeletonData using a method other than resource names #2595

Closed yxdtg closed 3 months ago

yxdtg commented 3 months ago

Below is a function I am using. Could you please advise on what needs to be changed?

function parseSkeletonData(skeletonData: Uint8Array, atlasData: spine.TextureAtlas, texture: PIXI.Texture, skeletonDataName: string = "", atlasDataName: string = "", options?: spine.ISpineOptions): spine.SkeletonData {
    const cacheKey = `${skeletonDataName}-${atlasDataName}-${options?.scale ?? 1}`;

    let skeleton = spine.Spine.skeletonCache[cacheKey];
    if (skeleton) {
        return skeleton;
    }

    atlasData.pages.forEach((page) => {
        if (texture) {
            page.texture = spine.SpineTexture.from(texture.baseTexture);
        } else {
            console.warn(`Texture for page ${page.name} not found in provided images.`);
        }
    });

    const attachmentLoader = new spine.AtlasAttachmentLoader(atlasData);
    let parser = skeletonData instanceof Uint8Array ? new spine.SkeletonBinary(attachmentLoader) : new spine.SkeletonJson(attachmentLoader);
    parser.scale = options?.scale ?? 1;
    skeleton = parser.readSkeletonData(skeletonData);

    spine.Spine.skeletonCache[cacheKey] = skeleton;

    return skeleton;
}
davidetan commented 3 months ago

Below is a function I am using. Could you please advise on what needs to be changed?

function parseSkeletonData(skeletonData: Uint8Array, atlasData: spine.TextureAtlas, texture: PIXI.Texture, skeletonDataName: string = "", atlasDataName: string = "", options?: spine.ISpineOptions): spine.SkeletonData {
    const cacheKey = `${skeletonDataName}-${atlasDataName}-${options?.scale ?? 1}`;

    let skeleton = spine.Spine.skeletonCache[cacheKey];
    if (skeleton) {
        return skeleton;
    }

    atlasData.pages.forEach((page) => {
        if (texture) {
            page.texture = spine.SpineTexture.from(texture.baseTexture);
        } else {
            console.warn(`Texture for page ${page.name} not found in provided images.`);
        }
    });

    const attachmentLoader = new spine.AtlasAttachmentLoader(atlasData);
    let parser = skeletonData instanceof Uint8Array ? new spine.SkeletonBinary(attachmentLoader) : new spine.SkeletonJson(attachmentLoader);
    parser.scale = options?.scale ?? 1;
    skeleton = parser.readSkeletonData(skeletonData);

    spine.Spine.skeletonCache[cacheKey] = skeleton;

    return skeleton;
}

The function provided is mostly correct. There are mainly two problems.

1) It will work only when you have a single page atlas. When your atlas has multiple pages, it will not work because it sets for all the pages the same png.

2) You are setting the texture on the atlas pages only. A page holds references to the regions that need to have the texture set too. To do that automatically, you should use the setTexture (texture: Texture) method of the TextureAtlasPage. This will set the texture to the page and to all its regions.

My advice is to update your function replacing the forEach with this one:

atlasData.pages.forEach((page, index) => {
    const texture = textures[index];
    if (texture) {
        page.setTexture(SpineTexture.from(texture.baseTexture));
    } else {
        console.warn(`Texture for page ${page.name} not found in provided images.`);
    }
});

and updating its signature by changing the texture parameter to be textures: Array<Texture>.

I'll close the issue right now since this is not a bug. If you have other issues, please explain them in a detailed way.