Nate wroteIt is part of the configuration of SkeletonJson and SkeletonBinary when loading skeleton data. Eg, with spine-libgdx, instead of the usual
I agree with you that a code with spine-libgdx looks easy with anonymous classes and it's beautiful overrides, but nevertheless it is a java. And what about C++? Specifically, I'm interested in spine-cocos2d-x interface, is it possible to get the same with a minimum of effort? Often I use:
SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
How can I add a prefix with cocos2d-x? I myself will answer this question, it's not easy, because there is no OOP and OOD:
#include <spine/Cocos2dAttachmentLoader.h>
#include <spine/AttachmentVertices.h>
#include <spine/extension.h>
struct CustomAttachmentLoader {
spAttachmentLoader super;
spAtlasAttachmentLoader* atlasAttachmentLoader;
std::string key;
};
static unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
// just general approach
spAttachment* _CustomAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type,
const char* name, const char* path) {
CustomAttachmentLoader* self = SUB_CAST(CustomAttachmentLoader, loader);
std::string newPath = self->key + "/";
newPath += path;
return spAttachmentLoader_createAttachment(SUPER(self->atlasAttachmentLoader), skin, type, name, newPath.c_str());
}
void _CustomAttachmentLoader_configureAttachment (spAttachmentLoader* loader, spAttachment* attachment) {
attachment->attachmentLoader = loader;
switch (attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment);
spAtlasRegion* region = (spAtlasRegion*)regionAttachment->rendererObject;
AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject, 4, quadTriangles, 6);
V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts;
for (int i = 0, ii = 0; i < 4; ++i, ii += 2) {
vertices[i].texCoords.u = regionAttachment->uvs[ii];
vertices[i].texCoords.v = regionAttachment->uvs[ii + 1];
}
regionAttachment->rendererObject = attachmentVertices;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment);
spAtlasRegion* region = (spAtlasRegion*)meshAttachment->rendererObject;
AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject,
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];
}
meshAttachment->rendererObject = attachmentVertices;
break;
}
default: ;
}
}
void _CustomAttachmentLoader_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 _CustomAttachmentLoader_dispose (spAttachmentLoader* loader) {
CustomAttachmentLoader* self = SUB_CAST(CustomAttachmentLoader, loader);
spAttachmentLoader_dispose(SUPER_CAST(spAttachmentLoader, self->atlasAttachmentLoader));
_spAttachmentLoader_deinit(loader);
}
RichAnimation::RichAnimation(const std::string& prefix) : _prefix(prefix) {
}
RichAnimation* RichAnimation::createWithJsonFile (const std::string& prefix, const std::string& skeletonJsonFile, spAtlas* atlas, float scale) {
RichAnimation* node = new RichAnimation(prefix);
node->initWithJsonFileExtend(skeletonJsonFile, atlas, scale);
node->autorelease();
return node;
}
RichAnimation* RichAnimation::createWithJsonFile (const std::string& prefix, const std::string& skeletonJsonFile, const std::string& atlasFile, float scale) {
RichAnimation* node = new RichAnimation(prefix);
spAtlas* atlas = spAtlas_createFromFile(atlasFile.c_str(), 0);
node->initWithJsonFileExtend(skeletonJsonFile, atlas, scale);
node->autorelease();
return node;
}
RichAnimation* RichAnimation::createWithBinaryFile (const std::string& prefix, const std::string& skeletonBinaryFile, spAtlas* atlas, float scale) {
RichAnimation* node = new RichAnimation(prefix);
node->initWithBinaryFileExtend(skeletonBinaryFile, atlas, scale);
node->autorelease();
return node;
}
RichAnimation* RichAnimation::createWithBinaryFile (const std::string& prefix, const std::string& skeletonBinaryFile, const std::string& atlasFile, float scale) {
RichAnimation* node = new RichAnimation(prefix);
spAtlas* atlas = spAtlas_createFromFile(atlasFile.c_str(), 0);
node->initWithBinaryFileExtend(skeletonBinaryFile, atlas, scale);
node->autorelease();
return node;
}
void RichAnimation::initWithJsonFileExtend (const std::string& skeletonDataFile, spAtlas* atlas, float scale) {
_atlas = atlas;
createCustomAttachmentLoader(_atlas);
spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader);
json->scale = scale;
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str());
CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data.");
spSkeletonJson_dispose(json);
setSkeletonData(skeletonData, true);
initialize();
}
void RichAnimation::initWithJsonFileExtend (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
_atlas = spAtlas_createFromFile(atlasFile.c_str(), 0);
CCASSERT(_atlas, "Error reading atlas file.");
createCustomAttachmentLoader(_atlas);
spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader);
json->scale = scale;
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str());
CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data file.");
spSkeletonJson_dispose(json);
setSkeletonData(skeletonData, true);
initialize();
}
void RichAnimation::initWithBinaryFileExtend (const std::string& skeletonDataFile, spAtlas* atlas, float scale) {
_atlas = atlas;
createCustomAttachmentLoader(_atlas);
spSkeletonBinary* binary = spSkeletonBinary_createWithLoader(_attachmentLoader);
binary->scale = scale;
spSkeletonData* skeletonData = spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str());
CCASSERT(skeletonData, binary->error ? binary->error : "Error reading skeleton data file.");
spSkeletonBinary_dispose(binary);
setSkeletonData(skeletonData, true);
initialize();
}
void RichAnimation::initWithBinaryFileExtend (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) {
_atlas = spAtlas_createFromFile(atlasFile.c_str(), 0);
CCASSERT(_atlas, "Error reading atlas file.");
createCustomAttachmentLoader(_atlas);
spSkeletonBinary* binary = spSkeletonBinary_createWithLoader(_attachmentLoader);
binary->scale = scale;
spSkeletonData* skeletonData = spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str());
CCASSERT(skeletonData, binary->error ? binary->error : "Error reading skeleton data file.");
spSkeletonBinary_dispose(binary);
setSkeletonData(skeletonData, true);
initialize();
}
void RichAnimation::createCustomAttachmentLoader (spAtlas* atlas) {
CustomAttachmentLoader* self = NEW(CustomAttachmentLoader);
_spAttachmentLoader_init(SUPER(self), _CustomAttachmentLoader_dispose, _CustomAttachmentLoader_createAttachment,
_CustomAttachmentLoader_configureAttachment, _CustomAttachmentLoader_disposeAttachment);
self->atlasAttachmentLoader = spAtlasAttachmentLoader_create(atlas);
self->key = _prefix;
_attachmentLoader = &self->super;
}