mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +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
|
## Notes
|
||||||
|
|
||||||
- Images are premultiplied by cocos2d-x, so the Spine atlas images should *not* use premultiplied alpha.
|
* 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.
|
* 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
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,7 @@ bool BatchingExample::init () {
|
|||||||
|
|
||||||
int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
|
int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
|
||||||
int yMin = 0, yMax = _contentSize.height * 0.7f;
|
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.
|
// Each skeleton node shares the same atlas, skeleton data, and mix times.
|
||||||
SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
|
SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
|
||||||
skeletonNode->setAnimationStateData(_stateData);
|
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, "jump", true, RandomHelper::random_int(0, 300) / 100.0f);
|
||||||
skeletonNode->addAnimation(0, "run", true);
|
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(
|
skeletonNode->setPosition(Vec2(
|
||||||
RandomHelper::random_int(xMin, xMax),
|
RandomHelper::random_int(xMin, xMax),
|
||||||
|
|||||||
@ -67,7 +67,6 @@ void SkeletonRenderer::initialize () {
|
|||||||
setOpacityModifyRGB(true);
|
setOpacityModifyRGB(true);
|
||||||
|
|
||||||
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
|
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP));
|
||||||
setTwoColorTint(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsSkeletonData) {
|
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) {
|
if (_debugSlots || _debugBones) {
|
||||||
drawDebug(renderer, transform, transformFlags);
|
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* 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();
|
TwoColorTrianglesCommand* command = nextFreeCommand();
|
||||||
command->init(globalOrder, textureID, glProgramState, blendType, triangles, mv, flags);
|
command->init(globalOrder, textureID, glProgramState, blendType, triangles, mv, flags);
|
||||||
renderer->addCommand(command);
|
renderer->addCommand(command);
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user