getCascadeBoundingBox is not working in some cases?

getCascadeBoundingBox is not working in some cases?
0.0 0

#1

Hi all,

I have a problem that I did not succeed in resoving for several days… Let me explain my case.

I use Spine SkeletonAnimation (which are very cool :smiley: !), but when you instanciate such an animation with a json + atlas exported file, you obtain a Node with an anchor point set to (0, 0), but a bounding box with a negative origin (in x and in y) : the animation render goes "around the anchor point… OK, for the moment, that’s not a problem… But, in my game, I need to present my animation with a title, so to do that, I just created a parent node with the required size (title + animation size), and then I add as child the title, and the SkeletonAnimation… It works well. But, my problem is that in my use case I need to call the utils::getCascadeBoundingBox (to put this new node some UI Widget)… And I think this function is not working in this case, probably due due to this “negative values bounding box origin” : when I call the utils::getCascadeBoundingBox on my new created node, I obtain a bounding box which is not the one I can see on the screen ! Its origin coordinates are negative while I have been careful that it does not happen by offseting the animation child node to compensate the bounding box negative origin.

I copy here the lines which are problematic

I took a look to the implementation of getCascadeBoundingBox and I think there is a problem in it : Let’s see that code : the last line of the function permits to take into account the current node bouding box

		// merge content size
		if (contentSize.width > 0 && contentSize.height > 0)
		{
			const Rect box = RectApplyAffineTransform(Rect(0, 0, contentSize.width, contentSize.height), node->getNodeToWorldAffineTransform());
			if (!merge)
			{
				cbb = box;
			}
			else
			{
				cbb.merge(box);
			}
		}

I think it can not work since when you have graphical data outside the area (0,0, width, height), and that is the case when the bouding box has a negative origin, it returns the bounding box corresponding to the area (0,0, width, height) ! So I created my own getCascadeBoundingBox with this correction

		// merge content size
		if (contentSize.width > 0 && contentSize.height > 0)
		{
			Vec2 localOrigin = node->getBoundingBox().origin - node->getPosition() + node->getAnchorPointInPoints();
			const Rect box = RectApplyAffineTransform(Rect(localOrigin.x, localOrigin.y, contentSize.width, contentSize.height), node->getNodeToWorldAffineTransform());
			if (!merge)
			{
				cbb = box;
			}
			else
			{
				cbb.merge(box);
			}
		}

The result is better (near to the correct bounding box) but the resulting bounding box is still not the correct one !

Does anybody have an idea ? I hope somebody understand my problem (since it is difficult to explain with my frenchy english :joy:).

Thanks for your help !

Olivier.


#2

Hi all

I just find a solution to my problem. I think that Nodes with negative x or / and y bounding box origin are badly handled in cocos2d-x :sob: !!

Let’s take an example : if you create a Spine SkeletonAnimation, you will get a Node with a negative x and y bounding box origin. Let’s put this animation into another node, just to illustrate the problem (in my case I just wanted to add a text title bellow my animation, but here to simplify the problem I)

Node* rootNode = Node::create();
rootNode->setContentSize(Size(600,600);
auto spineAnim = new SkeletonAnimation("SpineBoy.json", "SpineBoy.atlas");
// Set the anim content size
spineAnim->setContentSize(spineAnim->getBoundingBox().size);
Node* newNode = Node::create();
newNode->setContentSize(spineAnim->getContentSize());
// Add the animation in the middle of the new node
Vec2 middle = (newNode->getContentSize() - _renderNode->getContentSize()) / 2;
// The animation position must be offsetted with bounding box origin to be really centered !
spineAnim->setPosition(middle + _renderNode->getBoundingBox().origin - _renderNode->getPosition());
newNode->addChild(spineAnim);
newNode->setPosition(300, 20);
rootNode->addChild(newNode);

For the moment, there is no problem. Note that if a child is added in the animation, it will be added from the point (0,0) of the bounding box, not from the left bottom corner of it ! I don’t know if it is normal… :disappointed_relieved: The problem I saw with getCascadeBoundingBox is that when you call it on such a node, it don’t work ! Lets see : if we call it like this

auto cascadeBB = utils::getCascadeBoundingBox(newNode);

the returned bounding box has some negative values in origin while it should not ! If you call a simple getBoundingBox like this

auto bb = newNode->getBoundingBox()

it works ! The bounding box is correct ! I think this is a bug, no ?

I made my own implementation of getCascadeBoundingBox, with this code, and I think it works !

static Rect getCascadeBoundingBox(Node *node)
{
	Rect cbb;
	Size contentSize = node->getContentSize();

	// check all children bounding box, get maximize box
	Node* child = nullptr;
	bool merge = false;
	for (auto object : node->getChildren())
	{
		child = dynamic_cast<Node*>(object);
		if (!child->isVisible()) continue;

		Rect box = getCascadeBoundingBox(child);
		box.origin.x *= node->getScaleX();
		box.origin.y *= node->getScaleY();
		if (box.size.width <= 0 || box.size.height <= 0) continue;

		if (!merge)
		{
			cbb = box;
			merge = true;
		}
		else
		{
			cbb.merge(box);
		}
	}

	// merge with my bounding box
	if (contentSize.width > 0 && contentSize.height > 0)
	{
		Rect bb = node->getBoundingBox();
		if (node->getParent() == nullptr)
			// If no parent, bounding box is returned offsetted with anchor point
			bb.origin = bb.origin + node->getAnchorPointInPoints();
		if (!merge)
		{
			cbb = bb;
		}
		else
		{
			if (node->getParent() != nullptr)
				// Since bounding box must be returned in parent coordinates system, convert my chidren merged
				//	bounding boxes in this coordinates system before merge
				cbb.origin = cbb.origin + node->getPosition() - node->getAnchorPointInPoints();
			cbb.merge(bb);
		}
	}

	return cbb;
}

Is somebody interrested with this problem ?
Or am I alone in a sort of 4th dimension :joy: !

Note that this bad management of “negative bounding box origin” is effective to in the UI Widgets, and I made a fix in some files (in UILayoutManager and UIWidget classes).

I hope this will help somebody !

See yaa !

Olivier.