dhuang11

We are a Spine licensee and doing our first Spine deployment. It works great, but we'd like to optimize it into our workflow/toolchain a bit neater.

To reduce image duplication, I'm trying to load the images used by Spine animations from the Cocos2d-X SpriteFrameCache instead of from Spine's own atlases. I can get the code below to work and animations to play. However, the attachments are either rotated or scaled incorrectly.

for spRegionAttachment and spMeshAttachment, should the regionWidth and regionHeight be scaled based on the value used to create the skeleton? E.g. regionSize.width * json->scale?

Also for rotation, should we set this to 1 if the cocos2d-x image is rotated in its sprite sheet and 0 if it's not?

Any help would be greatly appreciated.
static unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};

spAttachment* _SpriteSheetAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type,
const char* name, const char* path) {
switch (type) {
case SP_ATTACHMENT_REGION: {
std::string spritePath = std::string(path) + ".png";
Sprite *region = Sprite::createWithSpriteFrameName(spritePath);
if(!region) {
_spAttachmentLoader_setError(loader, "SpriteFrame not found with path: ", path);
CC_SAFE_DELETE(region);
return 0;
}
spRegionAttachment* attachment;
const cocos2d::Size& regionSize = region->getContentSize();
const V3F_C4B_T2F_Quad spriteQuad = region->getQuad();
attachment = spRegionAttachment_create(name);
attachment->rendererObject = region;
region->retain();
spRegionAttachment_setUVs(attachment,
spriteQuad.bl.texCoords.u,
spriteQuad.bl.texCoords.v,
spriteQuad.tr.texCoords.u,
spriteQuad.tr.texCoords.v,
0);
attachment->regionOffsetX = 0;
attachment->regionOffsetY = 0;
attachment->regionWidth = regionSize.width;
attachment->regionHeight = regionSize.height;
attachment->regionOriginalWidth = regionSize.width;
attachment->regionOriginalHeight = regionSize.height;
return SUPER(attachment);
}
case SP_ATTACHMENT_MESH:
case SP_ATTACHMENT_LINKED_MESH: {
std::string spritePath = std::string(path) + ".png";
Sprite *region = Sprite::createWithSpriteFrameName(spritePath);
if(!region) {
_spAttachmentLoader_setError(loader, "SpriteFrame not found with path: ", path);
CC_SAFE_DELETE(region);
return 0;
}
spMeshAttachment* attachment;
const cocos2d::Size& regionSize = region->getContentSize();
const V3F_C4B_T2F_Quad spriteQuad = region->getQuad();
attachment = spMeshAttachment_create(name);
attachment->rendererObject = region;
region->retain();
attachment->regionU = spriteQuad.bl.texCoords.u;
attachment->regionV = spriteQuad.bl.texCoords.v;
attachment->regionU2 = spriteQuad.tr.texCoords.u;
attachment->regionV2 = spriteQuad.tr.texCoords.v;
attachment->regionOffsetX = region->getOffsetPosition().x;
attachment->regionOffsetY = region->getOffsetPosition().y;
attachment->regionRotate = 1;
attachment->regionWidth = regionSize.width;
attachment->regionHeight = regionSize.height;
attachment->regionOriginalWidth = regionSize.width;
attachment->regionOriginalHeight = regionSize.height;
return SUPER(SUPER(attachment));
}
case SP_ATTACHMENT_BOUNDING_BOX:
return SUPER(SUPER(spBoundingBoxAttachment_create(name)));
case SP_ATTACHMENT_PATH:
return SUPER(SUPER(spPathAttachment_create(name)));
default:
_spAttachmentLoader_setUnknownTypeError(loader, type);
return 0;
}
}

void _SpriteSheetAttachmentLoader_configureAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
attachment->attachmentLoader = loader;

switch (attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);

//Getting region from sprite
Sprite* region = (Sprite*)regionAttachment->rendererObject;

// Create vertex aatachment from sprite texture
AttachmentVertices* attachmentVertices = new AttachmentVertices(region->getTexture(), 4, quadTriangles, 6);
V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;

// Create uv's from sprite quad
const V3F_C4B_T2F_Quad& spriteQuad = region->getQuad();
vertices[1].texCoords = spriteQuad.tl.texCoords;
vertices[2].texCoords = spriteQuad.tr.texCoords;
vertices[3].texCoords = spriteQuad.br.texCoords;
vertices[0].texCoords = spriteQuad.bl.texCoords;

//Sefty delete sprite
region->release();

regionAttachment->rendererObject = attachmentVertices;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
//Getting region from sprite
Sprite* region = (Sprite*)meshAttachment->rendererObject;
AttachmentVertices* attachmentVertices = new AttachmentVertices(region->getTexture(),
meshAttachment->super.worldVerticesLength >> 1, meshAttachment->triangles, meshAttachment->trianglesCount);
V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;
for (int i = 0, ii = 0, nn = meshAttachment->super.worldVerticesLength; ii < nn; ++i, ii += 2) {
vertices[i].texCoords.u = meshAttachment->uvs[ii];
vertices[i].texCoords.v = meshAttachment->uvs[ii + 1];
}

region->release();
meshAttachment->rendererObject = attachmentVertices;
break;
}
default: ;
}
}

void _SpriteSheetAttachmentLoader_disposeAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
switch (attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);
delete (AttachmentVertices*)regionAttachment->rendererObject;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
delete (AttachmentVertices*)meshAttachment->rendererObject;
break;
}
default: ;
}
}

void _SpriteSheetAttachmentLoader_dispose (spAttachmentLoader* loader) {
SpriteSheetAttachmentLoader* self = SUB_CAST(SpriteSheetAttachmentLoader, loader);
spAttachmentLoader_dispose(SUPER_CAST(spAttachmentLoader, self->atlasAttachmentLoader));
_spAttachmentLoader_deinit(loader);
}

SpriteSheetAttachmentLoader* SpriteSheetAttachmentLoader_create (spAtlas* atlas) {
SpriteSheetAttachmentLoader* self = NEW(SpriteSheetAttachmentLoader);
_spAttachmentLoader_init(SUPER(self), _SpriteSheetAttachmentLoader_dispose, _SpriteSheetAttachmentLoader_createAttachment,
_SpriteSheetAttachmentLoader_configureAttachment, _SpriteSheetAttachmentLoader_disposeAttachment);
self->atlasAttachmentLoader = spAtlasAttachmentLoader_create(atlas);
return self;
}


---

No help?
dhuang11
  • Posts: 2

badlogic

The region size doesn't need to be scaled by json->scale. Are the images in your SpriteFrameCache rotated, scaled or whitespace stripped?
User avatar
badlogic

Mario
  • Posts: 1936

dhuang11

badlogic wrote:The region size doesn't need to be scaled by json->scale. Are the images in your SpriteFrameCache rotated, scaled or whitespace stripped?
Hi - Yes they could be rotated - not always. None of the images are actually scaled in software. They are scaled when packed to match a specific resolution type (e.g. HD vs SD) and they all are most likely whitespace stripped.
dhuang11
  • Posts: 2

badlogic

Since I can't reproduce this on my end, I can only try to stab in the dark a little. I'd debug it by resolution matching, disabling rotation and whitespace stripping and then work my way up. I'd also use a simplified skeleton with only a region and mesh attachment to make debugging easier. I'm afraid I don't have any other tips beside that. The code you posted looks OK, without knowing how the underlying atlas returns region sizes and compensates for rotation/whitespace stripping etc.
User avatar
badlogic

Mario
  • Posts: 1936

TianT

dhuang11 wrote:We are a Spine licensee and doing our first Spine deployment. It works great, but we'd like to optimize it into our workflow/toolchain a bit neater.

To reduce image duplication, I'm trying to load the images used by Spine animations from the Cocos2d-X SpriteFrameCache instead of from Spine's own atlases. I can get the code below to work and animations to play. However, the attachments are either rotated or scaled incorrectly.

for spRegionAttachment and spMeshAttachment, should the regionWidth and regionHeight be scaled based on the value used to create the skeleton? E.g. regionSize.width * json->scale?

Also for rotation, should we set this to 1 if the cocos2d-x image is rotated in its sprite sheet and 0 if it's not?

Any help would be greatly appreciated.
static unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};

spAttachment* _SpriteSheetAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type,
const char* name, const char* path) {
switch (type) {
case SP_ATTACHMENT_REGION: {
std::string spritePath = std::string(path) + ".png";
Sprite *region = Sprite::createWithSpriteFrameName(spritePath);
if(!region) {
_spAttachmentLoader_setError(loader, "SpriteFrame not found with path: ", path);
CC_SAFE_DELETE(region);
return 0;
}
spRegionAttachment* attachment;
const cocos2d::Size& regionSize = region->getContentSize();
const V3F_C4B_T2F_Quad spriteQuad = region->getQuad();
attachment = spRegionAttachment_create(name);
attachment->rendererObject = region;
region->retain();
spRegionAttachment_setUVs(attachment,
spriteQuad.bl.texCoords.u,
spriteQuad.bl.texCoords.v,
spriteQuad.tr.texCoords.u,
spriteQuad.tr.texCoords.v,
0);
attachment->regionOffsetX = 0;
attachment->regionOffsetY = 0;
attachment->regionWidth = regionSize.width;
attachment->regionHeight = regionSize.height;
attachment->regionOriginalWidth = regionSize.width;
attachment->regionOriginalHeight = regionSize.height;
return SUPER(attachment);
}
case SP_ATTACHMENT_MESH:
case SP_ATTACHMENT_LINKED_MESH: {
std::string spritePath = std::string(path) + ".png";
Sprite *region = Sprite::createWithSpriteFrameName(spritePath);
if(!region) {
_spAttachmentLoader_setError(loader, "SpriteFrame not found with path: ", path);
CC_SAFE_DELETE(region);
return 0;
}
spMeshAttachment* attachment;
const cocos2d::Size& regionSize = region->getContentSize();
const V3F_C4B_T2F_Quad spriteQuad = region->getQuad();
attachment = spMeshAttachment_create(name);
attachment->rendererObject = region;
region->retain();
attachment->regionU = spriteQuad.bl.texCoords.u;
attachment->regionV = spriteQuad.bl.texCoords.v;
attachment->regionU2 = spriteQuad.tr.texCoords.u;
attachment->regionV2 = spriteQuad.tr.texCoords.v;
attachment->regionOffsetX = region->getOffsetPosition().x;
attachment->regionOffsetY = region->getOffsetPosition().y;
attachment->regionRotate = 1;
attachment->regionWidth = regionSize.width;
attachment->regionHeight = regionSize.height;
attachment->regionOriginalWidth = regionSize.width;
attachment->regionOriginalHeight = regionSize.height;
return SUPER(SUPER(attachment));
}
case SP_ATTACHMENT_BOUNDING_BOX:
return SUPER(SUPER(spBoundingBoxAttachment_create(name)));
case SP_ATTACHMENT_PATH:
return SUPER(SUPER(spPathAttachment_create(name)));
default:
_spAttachmentLoader_setUnknownTypeError(loader, type);
return 0;
}
}

void _SpriteSheetAttachmentLoader_configureAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
attachment->attachmentLoader = loader;

switch (attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);

//Getting region from sprite
Sprite* region = (Sprite*)regionAttachment->rendererObject;

// Create vertex aatachment from sprite texture
AttachmentVertices* attachmentVertices = new AttachmentVertices(region->getTexture(), 4, quadTriangles, 6);
V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;

// Create uv's from sprite quad
const V3F_C4B_T2F_Quad& spriteQuad = region->getQuad();
vertices[1].texCoords = spriteQuad.tl.texCoords;
vertices[2].texCoords = spriteQuad.tr.texCoords;
vertices[3].texCoords = spriteQuad.br.texCoords;
vertices[0].texCoords = spriteQuad.bl.texCoords;

//Sefty delete sprite
region->release();

regionAttachment->rendererObject = attachmentVertices;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
//Getting region from sprite
Sprite* region = (Sprite*)meshAttachment->rendererObject;
AttachmentVertices* attachmentVertices = new AttachmentVertices(region->getTexture(),
meshAttachment->super.worldVerticesLength >> 1, meshAttachment->triangles, meshAttachment->trianglesCount);
V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;
for (int i = 0, ii = 0, nn = meshAttachment->super.worldVerticesLength; ii < nn; ++i, ii += 2) {
vertices[i].texCoords.u = meshAttachment->uvs[ii];
vertices[i].texCoords.v = meshAttachment->uvs[ii + 1];
}

region->release();
meshAttachment->rendererObject = attachmentVertices;
break;
}
default: ;
}
}

void _SpriteSheetAttachmentLoader_disposeAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
switch (attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);
delete (AttachmentVertices*)regionAttachment->rendererObject;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
delete (AttachmentVertices*)meshAttachment->rendererObject;
break;
}
default: ;
}
}

void _SpriteSheetAttachmentLoader_dispose (spAttachmentLoader* loader) {
SpriteSheetAttachmentLoader* self = SUB_CAST(SpriteSheetAttachmentLoader, loader);
spAttachmentLoader_dispose(SUPER_CAST(spAttachmentLoader, self->atlasAttachmentLoader));
_spAttachmentLoader_deinit(loader);
}

SpriteSheetAttachmentLoader* SpriteSheetAttachmentLoader_create (spAtlas* atlas) {
SpriteSheetAttachmentLoader* self = NEW(SpriteSheetAttachmentLoader);
_spAttachmentLoader_init(SUPER(self), _SpriteSheetAttachmentLoader_dispose, _SpriteSheetAttachmentLoader_createAttachment,
_SpriteSheetAttachmentLoader_configureAttachment, _SpriteSheetAttachmentLoader_disposeAttachment);
self->atlasAttachmentLoader = spAtlasAttachmentLoader_create(atlas);
return self;
}


---

No help?
----------------------------------------
did you solved it ?
User avatar
TianT
  • Posts: 1


Return to Runtimes