Skip to content

Commit

Permalink
Fix the issue on the web where calling spine.setAttachment causes vis…
Browse files Browse the repository at this point in the history
…ual glitches due to using incorrect textures.
  • Loading branch information
bofeng-song committed Dec 4, 2024
1 parent 01e98e8 commit 8d29401
Show file tree
Hide file tree
Showing 14 changed files with 116 additions and 62 deletions.
8 changes: 4 additions & 4 deletions cocos/spine/assembler/simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,14 @@ function realTimeTraverse (comp: Skeleton): void {
for (let i = 0; i < ic; i++) ibuf[i] += chunkOffset;

const data = model.getData();
const textures = model.getTextures();
const count = data.size();
let indexOffset = 0;
let indexCount = 0;
for (let i = 0; i < count; i += 6) {
for (let i = 0; i < count; i += 5) {
indexCount = data.get(i + 3);
const material = _getSlotMaterial(data.get(i + 4) as number, comp);
const textureID: number = data.get(i + 5);
comp.requestDrawData(material, textureID, indexOffset, indexCount);
comp.requestDrawData(material, textures.get(i / 5), indexOffset, indexCount);

Check failure on line 179 in cocos/spine/assembler/simple.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Unsafe argument of type `any` assigned to a parameter of type `string`
indexOffset += indexCount;
}

Expand Down Expand Up @@ -321,7 +321,7 @@ function cacheTraverse (comp: Skeleton): void {
const material = _getSlotMaterial(mesh.blendMode as number, comp);
const textureID = mesh.textureID;
indexCount = mesh.iCount;
comp.requestDrawData(material, textureID as number, indexOffset, indexCount);
comp.requestDrawData(material, textureID, indexOffset, indexCount);

Check failure on line 324 in cocos/spine/assembler/simple.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Unsafe argument of type `any` assigned to a parameter of type `string`
indexOffset += indexCount;
}

Expand Down
6 changes: 3 additions & 3 deletions cocos/spine/lib/spine-core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1208,16 +1208,16 @@ declare namespace spine {
setDebugMode(debug: boolean);
getDebugShapes();
resizeSlotRegion(slotName: string, width: number, height: number, createNew: boolean);
setSlotTexture(slotName: string, index: number);
setSlotTexture(slotName: string, uuid: string);
}

class wasmUtil {
static spineWasmInit(): void;
static spineWasmDestroy(): void;
static queryStoreMemory(size: number): number;
static querySpineSkeletonDataByUUID(uuid: string): SkeletonData;
static createSpineSkeletonDataWithJson(jsonStr: string, atlasText: string): SkeletonData;
static createSpineSkeletonDataWithBinary(byteSize: number, atlasText: string): SkeletonData;
static createSpineSkeletonDataWithJson(jsonStr: string, atlasText: string, textureNames: string[], textureUUIDs: string[]): SkeletonData;
static createSpineSkeletonDataWithBinary(byteSize: number, atlasText: string, textureNames: string[], textureUUIDs: string[]): SkeletonData;
static registerSpineSkeletonDataWithUUID(data: SkeletonData, uuid: string);
static destroySpineSkeletonDataWithUUID(uuid: string);
static destroySpineSkeleton(skeleton: Skeleton): void;
Expand Down
5 changes: 3 additions & 2 deletions cocos/spine/skeleton-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,13 @@ export class AnimationCache {
modelData.iData = iUint16Buf;

const data = model.getData();
const textures = model.getTextures();
const count = data.size();
for (let i = 0; i < count; i += 6) {
for (let i = 0; i < count; i += 5) {
const meshData = new SpineDrawItem();
meshData.iCount = data.get(i + 3);
meshData.blendMode = data.get(i + 4);
meshData.textureID = data.get(i + 5);
meshData.textureID = textures.get(i / 5);
modelData.meshes.push(meshData);
}

Expand Down
29 changes: 18 additions & 11 deletions cocos/spine/skeleton-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,25 @@ export class SkeletonData extends Asset {
const spData = spine.wasmUtil.querySpineSkeletonDataByUUID(uuid);
if (spData) {
this._skeletonCache = spData;
} else if (this._skeletonJson) {
this._skeletonCache = spine.wasmUtil.createSpineSkeletonDataWithJson(this.skeletonJsonStr, this._atlasText);
spine.wasmUtil.registerSpineSkeletonDataWithUUID(this._skeletonCache, uuid);
} else {
const rawData = new Uint8Array(this._nativeAsset);
const byteSize = rawData.length;
const ptr = spine.wasmUtil.queryStoreMemory(byteSize);
const wasmMem = spine.wasmUtil.wasm.HEAPU8.subarray(ptr, ptr + byteSize);
wasmMem.set(rawData);
this._skeletonCache = spine.wasmUtil.createSpineSkeletonDataWithBinary(byteSize, this._atlasText);
spine.wasmUtil.registerSpineSkeletonDataWithUUID(this._skeletonCache, uuid);
}
const size = this.textures.length;
let textureUUIDs = [] as string[];

Check failure on line 217 in cocos/spine/skeleton-data.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

'textureUUIDs' is never reassigned. Use 'const' instead
for (let i = 0; i < size; ++i) {
textureUUIDs.push(this.textures[i].uuid);
}
if (this._skeletonJson) {
this._skeletonCache = spine.wasmUtil.createSpineSkeletonDataWithJson(this.skeletonJsonStr, this._atlasText, this.textureNames, textureUUIDs);
spine.wasmUtil.registerSpineSkeletonDataWithUUID(this._skeletonCache, uuid);
} else {
const rawData = new Uint8Array(this._nativeAsset);
const byteSize = rawData.length;
const ptr = spine.wasmUtil.queryStoreMemory(byteSize);
const wasmMem = spine.wasmUtil.wasm.HEAPU8.subarray(ptr, ptr + byteSize);
wasmMem.set(rawData);
this._skeletonCache = spine.wasmUtil.createSpineSkeletonDataWithBinary(byteSize, this._atlasText, this.textureNames, textureUUIDs);
spine.wasmUtil.registerSpineSkeletonDataWithUUID(this._skeletonCache, uuid);
}
}

Check failure on line 233 in cocos/spine/skeleton-data.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

Expected indentation of 8 spaces but found 5

return this._skeletonCache;
}
Expand Down
26 changes: 4 additions & 22 deletions cocos/spine/skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { Graphics, UIRenderer } from '../2d';
import { Batcher2D } from '../2d/renderer/batcher-2d';
import { BlendFactor, BlendOp } from '../gfx';
import { MaterialInstance } from '../render-scene';
import { builtinResMgr } from '../asset/asset-manager';
import { assetManager, builtinResMgr } from '../asset/asset-manager';
import { legacyCC } from '../core/global-exports';
import { SkeletonSystem } from './skeleton-system';
import { RenderEntity, RenderEntityType } from '../2d/renderer/render-entity';
Expand All @@ -45,8 +45,6 @@ import { TrackEntryListeners } from './track-entry-listeners';
import { setPropertyEnumType } from '../core/internal-index';

const CachedFrameTime = 1 / 60;
const CUSTOM_SLOT_TEXTURE_BEGIN = 10000;
let _slotTextureID = CUSTOM_SLOT_TEXTURE_BEGIN;

type TrackListener = (x: spine.TrackEntry) => void;
type TrackListener2 = (x: spine.TrackEntry, ev: spine.Event | number) => void;
Expand Down Expand Up @@ -310,8 +308,6 @@ export class Skeleton extends UIRenderer {
*/
public _endSlotIndex;

private _slotTextures: Map<number, Texture2D> | null = null;

_vLength = 0;
_vBuffer: Uint8Array | null = null;
_iLength = 0;
Expand Down Expand Up @@ -1173,15 +1169,10 @@ export class Skeleton extends UIRenderer {
/**
* @engineInternal
*/
public requestDrawData (material: Material, textureID: number, indexOffset: number, indexCount: number): SkeletonDrawData {
public requestDrawData (material: Material, textureID: string, indexOffset: number, indexCount: number): SkeletonDrawData {
const draw = this._drawList.add();
draw.material = material;
if (textureID < CUSTOM_SLOT_TEXTURE_BEGIN) {
draw.texture = this._textures[textureID];
} else {
const texture = this._slotTextures?.get(textureID);
if (texture) draw.texture = texture;
}
draw.texture = assetManager.assets.get(textureID) as Texture2D;
draw.indexOffset = indexOffset;
draw.indexCount = indexCount;
return draw;
Expand Down Expand Up @@ -1867,16 +1858,7 @@ export class Skeleton extends UIRenderer {
const height = tex2d.height;
const createNewAttachment = createNew || false;
this._instance!.resizeSlotRegion(slotName, width, height, createNewAttachment);
if (!this._slotTextures) this._slotTextures = new Map<number, Texture2D>();
let textureID = 0;
this._slotTextures.forEach((value, key) => {
if (value === tex2d) textureID = key;
});
if (textureID === 0) {
textureID = ++_slotTextureID;
this._slotTextures.set(textureID, tex2d);
}
this._instance!.setSlotTexture(slotName, textureID);
this._instance!.setSlotTexture(slotName, tex2d.uuid);
}

private _destroySkeletonInfo (skeletonCache: SkeletonCache | null): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ using namespace spine;

static uint16_t quadTriangles[6] = {0, 1, 2, 2, 3, 0};

AttachmentVertices::AttachmentVertices(int verticesCount, uint16_t *triangles, int trianglesCount, uint32_t textureId) {
AttachmentVertices::AttachmentVertices(int verticesCount, uint16_t *triangles, int trianglesCount, spine::String textureId) {
_triangles = new Triangles();
_triangles->verts = new V3F_T2F_C4B[verticesCount];
_triangles->vertCount = verticesCount;
Expand Down Expand Up @@ -38,7 +38,7 @@ void AtlasAttachmentLoaderExtension::configureAttachment(Attachment *attachment)
auto *regionAttachment = static_cast<RegionAttachment *>(attachment);
auto &pages = _atlasCache->getPages();
auto *region = static_cast<AtlasRegion *>(regionAttachment->getRendererObject());
auto *attachmentVertices = new AttachmentVertices(4, quadTriangles, 6, pages.indexOf(region->page));
auto *attachmentVertices = new AttachmentVertices(4, quadTriangles, 6, region->page->name);
V3F_T2F_C4B *vertices = attachmentVertices->_triangles->verts;
const auto &uvs = regionAttachment->getUVs();
for (int i = 0, ii = 0; i < 4; ++i, ii += 2) {
Expand All @@ -51,7 +51,7 @@ void AtlasAttachmentLoaderExtension::configureAttachment(Attachment *attachment)
auto &pages = _atlasCache->getPages();
auto *region = static_cast<AtlasRegion *>(meshAttachment->getRendererObject());
auto *attachmentVertices = new AttachmentVertices(
static_cast<int32_t>(meshAttachment->getWorldVerticesLength() >> 1), meshAttachment->getTriangles().buffer(), static_cast<int32_t>(meshAttachment->getTriangles().size()), pages.indexOf(region->page));
static_cast<int32_t>(meshAttachment->getWorldVerticesLength() >> 1), meshAttachment->getTriangles().buffer(), static_cast<int32_t>(meshAttachment->getTriangles().size()), region->page->name);
V3F_T2F_C4B *vertices = attachmentVertices->_triangles->verts;
const auto &uvs = meshAttachment->getUVs();
for (size_t i = 0, ii = 0, nn = meshAttachment->getWorldVerticesLength(); ii < nn; ++i, ii += 2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

class AttachmentVertices {
public:
AttachmentVertices(int verticesCount, uint16_t *triangles, int trianglesCount, uint32_t textureId);
AttachmentVertices(int verticesCount, uint16_t *triangles, int trianglesCount, spine::String textureId);
virtual ~AttachmentVertices();
AttachmentVertices *copy();
Triangles *_triangles = nullptr;
uint32_t _textureId = 0;
spine::String _textureId{""};
};

class AtlasAttachmentLoaderExtension : public spine::AtlasAttachmentLoader {
Expand Down
11 changes: 6 additions & 5 deletions native/cocos/editor-support/spine-wasm/spine-model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ void SpineModel::addSlotMesh(SlotMesh& mesh, bool needMerge) {
bool canMerge = false;
auto count = _data.size();
if (needMerge && count > 0) {
if (_data[count - 2] == mesh.blendMode && _data[count - 1] == mesh.textureID) {
if (_data[count - 1] == mesh.blendMode && _textures[count / 5 - 1] == mesh.textureID) {
canMerge = true;
_data[count-4] += mesh.vCount;
_data[count-3] += mesh.iCount;
_data[count-3] += mesh.vCount;
_data[count-2] += mesh.iCount;
}
}
if (!canMerge) {
_data.setSize(count + 6, 0);
_data.setSize(count + 5, 0);
_data[count] = (uint32_t)mesh.vBuf;
_data[count + 1] = (uint32_t)mesh.iBuf;
_data[count + 2] = mesh.vCount;
_data[count + 3] = mesh.iCount;
_data[count + 4] = mesh.blendMode;
_data[count + 5] = mesh.textureID;
_textures.add(mesh.textureID);
}

auto indexCount = mesh.iCount;
Expand All @@ -45,6 +45,7 @@ void SpineModel::addSlotMesh(SlotMesh& mesh, bool needMerge) {

void SpineModel::clearMeshes() {
_data.setSize(0, 0);
_textures.setSize(0, "");
vCount = 0;
iCount = 0;
}
Expand Down
4 changes: 3 additions & 1 deletion native/cocos/editor-support/spine-wasm/spine-model.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SlotMesh {
uint32_t vCount{};
uint32_t iCount{};
uint32_t blendMode{};
uint32_t textureID{};
spine::String textureID{""};
};

class SpineModel {
Expand All @@ -31,8 +31,10 @@ class SpineModel {
void setBufferPtr(uint8_t* vp, uint16_t* ip);

spine::Vector<uint32_t>* getData();
inline spine::Vector<spine::String>* getTextures() { return &_textures; }
private:
spine::Vector<uint32_t> _data;
spine::Vector<spine::String> _textures;
public:
uint32_t vCount{};
uint32_t iCount{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ void SpineSkeletonInstance::resizeSlotRegion(const spine::String &slotName, uint
}
}

void SpineSkeletonInstance::setSlotTexture(const spine::String &slotName, uint32_t textureID) {
void SpineSkeletonInstance::setSlotTexture(const spine::String &slotName, spine::String textureID) {
if (!_skeleton) return;
auto* slot = _skeleton->findSlot(slotName);
if (!slot) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class SpineSkeletonInstance {
void onTrackEntryEvent(spine::TrackEntry *entry, spine::EventType type, spine::Event *event);
inline spine::Vector<SpineDebugShape> &getDebugShapes() { return _debugShapes; }
void resizeSlotRegion(const spine::String &slotName, uint32_t width, uint32_t height, bool createNew = false);
void setSlotTexture(const spine::String &slotName, uint32_t index);
void setSlotTexture(const spine::String &slotName, spine::String textureID);
void destroy();
bool isCache{false};
bool enable{true};
Expand All @@ -74,5 +74,5 @@ class SpineSkeletonInstance {
uint32_t _trackEntryListenerID = 0;
UserData _userData;
spine::Vector<SpineDebugShape> _debugShapes{};
spine::HashMap<spine::Slot*, uint32_t> _slotTextureSet{};
spine::HashMap<spine::Slot*, spine::String> _slotTextureSet{};
};
27 changes: 25 additions & 2 deletions native/cocos/editor-support/spine-wasm/spine-type-export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,7 @@ EMSCRIPTEN_BINDINGS(spine) {
.property("iCount", &SpineModel::iCount)
.property("vPtr", &SpineModel::vPtr)
.property("iPtr", &SpineModel::iPtr)
.function("getTextures", &SpineModel::getTextures, allow_raw_pointers())
.function("getData", &SpineModel::getData, allow_raw_pointer<SPVectorUint>());

class_<SpineDebugShape>("SpineDebugShape")
Expand Down Expand Up @@ -1384,8 +1385,30 @@ EMSCRIPTEN_BINDINGS(cocos_spine) {
.class_function("spineWasmDestroy", &SpineWasmUtil::spineWasmDestroy)
.class_function("queryStoreMemory", &SpineWasmUtil::queryStoreMemory)
.class_function("querySpineSkeletonDataByUUID", &SpineWasmUtil::querySpineSkeletonDataByUUID, allow_raw_pointers())
.class_function("createSpineSkeletonDataWithJson", &SpineWasmUtil::createSpineSkeletonDataWithJson, allow_raw_pointers())
.class_function("createSpineSkeletonDataWithBinary", &SpineWasmUtil::createSpineSkeletonDataWithBinary, allow_raw_pointers())
.class_function("createSpineSkeletonDataWithJson", optional_override([](String jsonStr, String atlasStr, emscripten::val nameArray, emscripten::val uuidArray){
unsigned count = nameArray["length"].as<unsigned>();
Vector<String> names = Vector<String>();
Vector<String> ids = Vector<String>();
names.setSize(count, "");
ids.setSize(count, "");
for (int i = 0; i < count; i++) {
names[i] = nameArray[i].as<String>();
ids[i] = uuidArray[i].as<String>();
}
return SpineWasmUtil::createSpineSkeletonDataWithJson(jsonStr, atlasStr, names, ids);
}), allow_raw_pointers())
.class_function("createSpineSkeletonDataWithBinary", optional_override([](uint32_t byteSize, String atlasStr, emscripten::val nameArray, emscripten::val uuidArray){
unsigned count = nameArray["length"].as<unsigned>();
Vector<String> names = Vector<String>();
Vector<String> ids = Vector<String>();
names.setSize(count, "");
ids.setSize(count, "");
for (int i = 0; i < count; i++) {
names[i] = nameArray[i].as<String>();
ids[i] = uuidArray[i].as<String>();
}
return SpineWasmUtil::createSpineSkeletonDataWithBinary(byteSize, atlasStr, names, ids);
}), allow_raw_pointers())
.class_function("registerSpineSkeletonDataWithUUID", &SpineWasmUtil::registerSpineSkeletonDataWithUUID, allow_raw_pointers())
.class_function("destroySpineSkeletonDataWithUUID", &SpineWasmUtil::destroySpineSkeletonDataWithUUID)
.class_function("destroySpineSkeleton", &SpineWasmUtil::destroySpineSkeleton, allow_raw_pointers())
Expand Down
Loading

0 comments on commit 8d29401

Please sign in to comment.