mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 09:16:01 +08:00
[cocos2dx] Batching of adjacent two color tinted skeletons. See README.md for rules on what does and doesn't break batching
This commit is contained in:
parent
4bb4c4d17a
commit
8c6a91c2a1
@ -69,8 +69,8 @@ The Spine cocos2d-x example works on Windows and Mac OS X.
|
||||
|
||||
## Notes
|
||||
|
||||
- Images are premultiplied by cocos2d-x, so the Spine atlas images should *not* use premultiplied alpha.
|
||||
- Two color tinting needs to be enabled on a per-skeleton basis. Call `SkeletonRenderer::setTwoColorTine(true)` or `SkeletonAnimation::setTwoColorTint(true)` after you created the skeleton instance. Note that two color tinting requires a custom shader and vertex format. Skeletons rendered with two color tinting can therefore not be batched with single color tinted skeletons or other 2D cocos2d-x elements like sprites. However, two-color tinted skeletons will be batched if possible when rendered after one another.
|
||||
* Images are premultiplied by cocos2d-x, so the Spine atlas images should *not* use premultiplied alpha.
|
||||
* Two color tinting needs to be enabled on a per-skeleton basis. Call `SkeletonRenderer::setTwoColorTine(true)` or `SkeletonAnimation::setTwoColorTint(true)` after you created the skeleton instance. Note that two color tinting requires a custom shader and vertex format. Skeletons rendered with two color tinting can therefore not be batched with single color tinted skeletons or other 2D cocos2d-x elements like sprites. However, two-color tinted skeletons will be batched if possible when rendered after one another. Attaching a child to a two color tinted skeleton will also break the batch.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ bool BatchingExample::init () {
|
||||
|
||||
int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
|
||||
int yMin = 0, yMax = _contentSize.height * 0.7f;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (int i = 0, j = 0; i < 50; i++) {
|
||||
// Each skeleton node shares the same atlas, skeleton data, and mix times.
|
||||
SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
|
||||
skeletonNode->setAnimationStateData(_stateData);
|
||||
@ -74,7 +74,11 @@ bool BatchingExample::init () {
|
||||
skeletonNode->addAnimation(0, "jump", true, RandomHelper::random_int(0, 300) / 100.0f);
|
||||
skeletonNode->addAnimation(0, "run", true);
|
||||
|
||||
// skeletonNode->setTwoColorTint(true);
|
||||
// alternative setting two color tint for groups of 10 skeletons
|
||||
// should end up with #skeletons / 10 batches
|
||||
if (j++ < 10)
|
||||
skeletonNode->setTwoColorTint(true);
|
||||
if (j == 20) j = 0;
|
||||
|
||||
skeletonNode->setPosition(Vec2(
|
||||
RandomHelper::random_int(xMin, xMax),
|
||||
|
||||
@ -67,7 +67,6 @@ void SkeletonRenderer::initialize () {
|
||||
setOpacityModifyRGB(true);
|
||||
|
||||
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
|
||||
setTwoColorTint(true);
|
||||
}
|
||||
|
||||
void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsSkeletonData) {
|
||||
@ -332,7 +331,42 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTwoColorTrianglesCommand) lastTwoColorTrianglesCommand->setForceFlush(true);
|
||||
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 (_debugSlots || _debugBones) {
|
||||
drawDebug(renderer, transform, transformFlags);
|
||||
|
||||
@ -226,7 +226,7 @@ V3F_C4B_C4B_T2F* SkeletonTwoColorBatch::allocateVertices(uint32_t numVertices) {
|
||||
TwoColorTrianglesCommand* SkeletonTwoColorBatch::addCommand(cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, cocos2d::BlendFunc blendType, const TwoColorTriangles& triangles, const cocos2d::Mat4& mv, uint32_t flags) {
|
||||
TwoColorTrianglesCommand* command = nextFreeCommand();
|
||||
command->init(globalOrder, textureID, glProgramState, blendType, triangles, mv, flags);
|
||||
renderer->addCommand(command);
|
||||
renderer->addCommand(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user