void HXSkeletonAnimation::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
SkeletonBatch* batch = SkeletonBatch::getInstance();
SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance();
bool isTwoColorTint = this->isTwoColorTint();
if (_effect) _effect->begin(_effect, _skeleton);
Color4F nodeColor;
nodeColor.r = getDisplayedColor().r / (float)255;
nodeColor.g = getDisplayedColor().g / (float)255;
nodeColor.b = getDisplayedColor().b / (float)255;
nodeColor.a = getDisplayedOpacity() / (float)255;
Color4F color;
Color4F darkColor;
AttachmentVertices* attachmentVertices = nullptr;
TwoColorTrianglesCommand* lastTwoColorTrianglesCommand = nullptr;
for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) {
spSlot* slot = _skeleton->drawOrder[i];
if (!slot->attachment) {
spSkeletonClipping_clipEnd(_clipper, slot);
continue;
}
cocos2d::TrianglesCommand::Triangles triangles;
TwoColorTriangles trianglesTwoColor;
switch (slot->attachment->type) {
case SP_ATTACHMENT_REGION: {
if(strcmp(slot->data->name,"face") == 0){
CCLOG("face slot SP_ATTACHMENT_REGION");
}
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
attachmentVertices = getAttachmentVertices(attachment);
if (!isTwoColorTint) {
triangles.indices = attachmentVertices->_triangles->indices;
triangles.indexCount = attachmentVertices->_triangles->indexCount;
triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount);
triangles.vertCount = attachmentVertices->_triangles->vertCount;
memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount);
spRegionAttachment_computeWorldVertices(attachment, slot->bone, (float*)triangles.verts, 0, 6);
} else {
trianglesTwoColor.indices = attachmentVertices->_triangles->indices;
trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount);
trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
for (int ii = 0; ii < trianglesTwoColor.vertCount; ii++) {
trianglesTwoColor.verts[ii].texCoords = attachmentVertices->_triangles->verts[ii].texCoords;
}
spRegionAttachment_computeWorldVertices(attachment, slot->bone, (float*)trianglesTwoColor.verts, 0, 7);
}
color.r = attachment->color.r;
color.g = attachment->color.g;
color.b = attachment->color.b;
color.a = attachment->color.a;
break;
}
case SP_ATTACHMENT_MESH: {
if(strcmp(slot->data->name,"face") == 0){
CCLOG("face slot SP_ATTACHMENT_MESH");
}
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
attachmentVertices = getAttachmentVertices(attachment);
if (!isTwoColorTint) {
triangles.indices = attachmentVertices->_triangles->indices;
triangles.indexCount = attachmentVertices->_triangles->indexCount;
triangles.verts = batch->allocateVertices(attachmentVertices->_triangles->vertCount);
triangles.vertCount = attachmentVertices->_triangles->vertCount;
memcpy(triangles.verts, attachmentVertices->_triangles->verts, sizeof(cocos2d::V3F_C4B_T2F) * attachmentVertices->_triangles->vertCount);
spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, triangles.vertCount * sizeof(cocos2d::V3F_C4B_T2F) / 4, (float*)triangles.verts, 0, 6);
} else {
trianglesTwoColor.indices = attachmentVertices->_triangles->indices;
trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
trianglesTwoColor.verts = twoColorBatch->allocateVertices(attachmentVertices->_triangles->vertCount);
trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
for (int ii = 0; ii < trianglesTwoColor.vertCount; ii++) {
trianglesTwoColor.verts[ii].texCoords = attachmentVertices->_triangles->verts[ii].texCoords;
}
spVertexAttachment_computeWorldVertices(SUPER(attachment), slot, 0, trianglesTwoColor.vertCount * sizeof(V3F_C4B_C4B_T2F) / 4, (float*)trianglesTwoColor.verts, 0, 7);
}
color.r = attachment->color.r;
color.g = attachment->color.g;
color.b = attachment->color.b;
color.a = attachment->color.a;
break;
}
case SP_ATTACHMENT_CLIPPING: {
if(strcmp(slot->data->name,"face") == 0){
CCLOG("face slot SP_ATTACHMENT_CLIPPING");
}
spClippingAttachment* clip = (spClippingAttachment*)slot->attachment;
spSkeletonClipping_clipStart(_clipper, slot, clip);
}
default:
if(strcmp(slot->data->name,"face") == 0){
CCLOG("face slot SP_ATTACHMENT_CLIPPING");
}
spSkeletonClipping_clipEnd(_clipper, slot);
continue;
}
if (slot->darkColor) {
darkColor.r = slot->darkColor->r * 255;
darkColor.g = slot->darkColor->g * 255;
darkColor.b = slot->darkColor->b * 255;
} else {
darkColor.r = 0;
darkColor.g = 0;
darkColor.b = 0;
}
color.a *= nodeColor.a * _skeleton->color.a * slot->color.a * 255;
// skip rendering if the color of this attachment is 0
if (color.a == 0){
spSkeletonClipping_clipEnd(_clipper, slot);
continue;
}
float multiplier = _premultipliedAlpha ? color.a : 255;
color.r *= nodeColor.r * _skeleton->color.r * slot->color.r * multiplier;
color.g *= nodeColor.g * _skeleton->color.g * slot->color.g * multiplier;
color.b *= nodeColor.b * _skeleton->color.b * slot->color.b * multiplier;
BlendFunc blendFunc;
switch (slot->data->blendMode) {
case SP_BLEND_MODE_ADDITIVE:
blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
blendFunc.dst = GL_ONE;
break;
case SP_BLEND_MODE_MULTIPLY:
blendFunc.src = GL_DST_COLOR;
blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
break;
case SP_BLEND_MODE_SCREEN:
blendFunc.src = GL_ONE;
blendFunc.dst = GL_ONE_MINUS_SRC_COLOR;
break;
default:
blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
}
if (!isTwoColorTint) {
if (spSkeletonClipping_isClipping(_clipper)) {
spSkeletonClipping_clipTriangles(_clipper, (float*)&triangles.verts[0].vertices, triangles.vertCount * sizeof(cocos2d::V3F_C4B_T2F) / 4, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, 6);
batch->deallocateVertices(triangles.vertCount);
if (_clipper->clippedTriangles->size == 0){
spSkeletonClipping_clipEnd(_clipper, slot);
continue;
}
triangles.vertCount = _clipper->clippedVertices->size >> 1;
triangles.verts = batch->allocateVertices(triangles.vertCount);
triangles.indexCount = _clipper->clippedTriangles->size;
triangles.indices = batch->allocateIndices(triangles.indexCount);
memcpy(triangles.indices, _clipper->clippedTriangles->items, sizeof(unsigned short) * _clipper->clippedTriangles->size);
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
float* verts = _clipper->clippedVertices->items;
float* uvs = _clipper->clippedUVs->items;
if (_effect) {
spColor light;
spColor dark;
light.r = color.r / 255.0f;
light.g = color.g / 255.0f;
light.b = color.b / 255.0f;
light.a = color.a / 255.0f;
dark.r = dark.g = dark.b = dark.a = 0;
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
spColor lightCopy = light;
spColor darkCopy = dark;
vertex->vertices.x = verts[vv];
vertex->vertices.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
_effect->transform(_effect, &vertex->vertices.x, &vertex->vertices.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
vertex->colors.r = (GLubyte)(lightCopy.r * 255);
vertex->colors.g = (GLubyte)(lightCopy.g * 255);
vertex->colors.b = (GLubyte)(lightCopy.b * 255);
vertex->colors.a = (GLubyte)(lightCopy.a * 255);
}
} else {
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
vertex->vertices.x = verts[vv];
vertex->vertices.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
vertex->colors.r = (GLubyte)color.r;
vertex->colors.g = (GLubyte)color.g;
vertex->colors.b = (GLubyte)color.b;
vertex->colors.a = (GLubyte)color.a;
}
}
} else {
cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
if (_effect) {
spColor light;
spColor dark;
light.r = color.r / 255.0f;
light.g = color.g / 255.0f;
light.b = color.b / 255.0f;
light.a = color.a / 255.0f;
dark.r = dark.g = dark.b = dark.a = 0;
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
spColor lightCopy = light;
spColor darkCopy = dark;
_effect->transform(_effect, &vertex->vertices.x, &vertex->vertices.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
vertex->colors.r = (GLubyte)(lightCopy.r * 255);
vertex->colors.g = (GLubyte)(lightCopy.g * 255);
vertex->colors.b = (GLubyte)(lightCopy.b * 255);
vertex->colors.a = (GLubyte)(lightCopy.a * 255);
}
} else {
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
vertex->colors.r = (GLubyte)color.r;
vertex->colors.g = (GLubyte)color.g;
vertex->colors.b = (GLubyte)color.b;
vertex->colors.a = (GLubyte)color.a;
}
}
}
} else {
if (spSkeletonClipping_isClipping(_clipper)) {
spSkeletonClipping_clipTriangles(_clipper, (float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.vertCount * sizeof(V3F_C4B_C4B_T2F) / 4, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, 7);
twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount);
if (_clipper->clippedTriangles->size == 0){
spSkeletonClipping_clipEnd(_clipper, slot);
continue;
}
trianglesTwoColor.vertCount = _clipper->clippedVertices->size >> 1;
trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount);
trianglesTwoColor.indexCount = _clipper->clippedTriangles->size;
trianglesTwoColor.indices = twoColorBatch->allocateIndices(trianglesTwoColor.indexCount);
memcpy(trianglesTwoColor.indices, _clipper->clippedTriangles->items, sizeof(unsigned short) * _clipper->clippedTriangles->size);
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
float* verts = _clipper->clippedVertices->items;
float* uvs = _clipper->clippedUVs->items;
if (_effect) {
spColor light;
spColor dark;
light.r = color.r / 255.0f;
light.g = color.g / 255.0f;
light.b = color.b / 255.0f;
light.a = color.a / 255.0f;
dark.r = darkColor.r / 255.0f;
dark.g = darkColor.g / 255.0f;
dark.b = darkColor.b / 255.0f;
dark.a = darkColor.a / 255.0f;
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
spColor lightCopy = light;
spColor darkCopy = dark;
vertex->position.x = verts[vv];
vertex->position.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
_effect->transform(_effect, &vertex->position.x, &vertex->position.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
vertex->color.r = (GLubyte)(lightCopy.r * 255);
vertex->color.g = (GLubyte)(lightCopy.g * 255);
vertex->color.b = (GLubyte)(lightCopy.b * 255);
vertex->color.a = (GLubyte)(lightCopy.a * 255);
vertex->color2.r = (GLubyte)(darkCopy.r * 255);
vertex->color2.g = (GLubyte)(darkCopy.g * 255);
vertex->color2.b = (GLubyte)(darkCopy.b * 255);
vertex->color2.a = 1;
}
} else {
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
vertex->position.x = verts[vv];
vertex->position.y = verts[vv + 1];
vertex->texCoords.u = uvs[vv];
vertex->texCoords.v = uvs[vv + 1];
vertex->color.r = (GLubyte)color.r;
vertex->color.g = (GLubyte)color.g;
vertex->color.b = (GLubyte)color.b;
vertex->color.a = (GLubyte)color.a;
vertex->color2.r = (GLubyte)darkColor.r;
vertex->color2.g = (GLubyte)darkColor.g;
vertex->color2.b = (GLubyte)darkColor.b;
vertex->color2.a = 1;
}
}
} else {
TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
if (_effect) {
spColor light;
spColor dark;
light.r = color.r / 255.0f;
light.g = color.g / 255.0f;
light.b = color.b / 255.0f;
light.a = color.a / 255.0f;
dark.r = darkColor.r / 255.0f;
dark.g = darkColor.g / 255.0f;
dark.b = darkColor.b / 255.0f;
dark.a = darkColor.a / 255.0f;
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
spColor lightCopy = light;
spColor darkCopy = dark;
_effect->transform(_effect, &vertex->position.x, &vertex->position.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
vertex->color.r = (GLubyte)(lightCopy.r * 255);
vertex->color.g = (GLubyte)(lightCopy.g * 255);
vertex->color.b = (GLubyte)(lightCopy.b * 255);
vertex->color.a = (GLubyte)(lightCopy.a * 255);
vertex->color2.r = (GLubyte)(darkCopy.r * 255);
vertex->color2.g = (GLubyte)(darkCopy.g * 255);
vertex->color2.b = (GLubyte)(darkCopy.b * 255);
vertex->color2.a = 1;
}
} else {
for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
vertex->color.r = (GLubyte)color.r;
vertex->color.g = (GLubyte)color.g;
vertex->color.b = (GLubyte)color.b;
vertex->color.a = (GLubyte)color.a;
vertex->color2.r = (GLubyte)darkColor.r;
vertex->color2.g = (GLubyte)darkColor.g;
vertex->color2.b = (GLubyte)darkColor.b;
vertex->color2.a = 1;
}
}
}
}
spSkeletonClipping_clipEnd(_clipper, slot);
}
spSkeletonClipping_clipEnd2(_clipper);
if (lastTwoColorTrianglesCommand) {
Node* parent = this->getParent();
// We need to decide if we can postpone flushing the current
// batch. We can postpone if the next sibling node is a
// two color tinted skeleton with the same global-z.
// The parent->getChildrenCount() > 100 check is a hack
// as checking for a sibling is an O(n) operation, and if
// all children of this nodes parent are skeletons, we
// are in O(n2) territory.
if (!parent || parent->getChildrenCount() > 100 || getChildrenCount() != 0) {
lastTwoColorTrianglesCommand->setForceFlush(true);
} else {
Vector<Node*>& children = parent->getChildren();
Node* sibling = nullptr;
for (ssize_t i = 0; i < children.size(); i++) {
if (children.at(i) == this) {
if (i < children.size() - 1) {
sibling = children.at(i+1);
break;
}
}
}
if (!sibling) {
lastTwoColorTrianglesCommand->setForceFlush(true);
} else {
SkeletonRenderer* siblingSkeleton = dynamic_cast<SkeletonRenderer*>(sibling);
if (!siblingSkeleton || // flush is next sibling isn't a SkeletonRenderer
!siblingSkeleton->isTwoColorTint() || // flush if next sibling isn't two color tinted
!siblingSkeleton->isVisible() || // flush if next sibling is two color tinted but not visible
(siblingSkeleton->getGlobalZOrder() != this->getGlobalZOrder())) { // flush if next sibling is two color tinted but z-order differs
lastTwoColorTrianglesCommand->setForceFlush(true);
}
}
}
}
if (_effect) _effect->end(_effect);
if (_debugSlots || _debugBones || _debugMeshes) {
drawDebug(renderer, transform, transformFlags);
}
}