Skip to content

Commit

Permalink
[scene2d.ui] Tree is more efficient when it has many nodes.
Browse files Browse the repository at this point in the history
For culling, node actors are stored as children of the tree in the order they are visible. We can use that to make assumptions on the node actor indices to minimize calls to Actor#getZIndex (which is a linear search).
  • Loading branch information
NathanSweet committed Oct 10, 2019
1 parent 3e20c26 commit 78ec523
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGES
@@ -1,6 +1,7 @@
[1.9.11]
- Update to LWJGL 3.2.3
- API Change: Table#getRow now returns -1 when over the table but not over a row (used to return the last row).
- API Change: Tree#addToTree and #removeFromTree now have an "int actorIndex" parameter.

[1.9.10]
- API Addition: Allow target display for maximization LWJGL3 backend
Expand Down
116 changes: 78 additions & 38 deletions gdx/src/com/badlogic/gdx/scenes/scene2d/ui/Tree.java
Expand Up @@ -153,18 +153,20 @@ public void insert (int index, N node) {
remove(node);
node.parent = null;
rootNodes.insert(index, node);
node.addToTree(this);
invalidateHierarchy();

int actorIndex = 0;
if (rootNodes.size > 1 && index > 0) actorIndex = rootNodes.get(index - 1).actor.getZIndex() + 1;
node.addToTree(this, actorIndex);
}

public void remove (N node) {
if (node.parent != null) {
node.parent.remove(node);
return;
}
rootNodes.removeValue(node, true);
node.removeFromTree(this);
invalidateHierarchy();
if (!rootNodes.removeValue(node, true)) return;
int actorIndex = node.actor.getZIndex();
if (actorIndex != -1) node.removeFromTree(this, actorIndex);
}

/** Removes all tree nodes. */
Expand Down Expand Up @@ -404,10 +406,13 @@ public Array<N> getRootNodes () {
* {@link #getRootNodes()}.
* @see Node#updateChildren() */
public void updateRootNodes () {
for (int i = rootNodes.size - 1; i >= 0; i--)
rootNodes.get(i).removeFromTree(this);
for (int i = 0, n = rootNodes.size; i < n; i++)
rootNodes.get(i).addToTree(this);
for (int i = 0, n = rootNodes.size; i < n; i++) {
N node = rootNodes.get(i);
int actorIndex = node.actor.getZIndex();
if (actorIndex != -1) node.removeFromTree(this, actorIndex);
}
for (int i = 0, n = rootNodes.size, actorIndex = 0; i < n; i++)
actorIndex += rootNodes.get(i).addToTree(this, actorIndex);
}

/** @return May be null. */
Expand Down Expand Up @@ -573,32 +578,36 @@ public void setExpanded (boolean expanded) {
if (children.size == 0) return;
Tree tree = getTree();
if (tree == null) return;
Object[] children = this.children.items;
int actorIndex = actor.getZIndex() + 1;
if (expanded) {
for (int i = 0, n = children.size; i < n; i++)
children.get(i).addToTree(tree);
for (int i = 0, n = this.children.size; i < n; i++)
actorIndex += ((N)children[i]).addToTree(tree, actorIndex);
} else {
for (int i = children.size - 1; i >= 0; i--)
children.get(i).removeFromTree(tree);
for (int i = 0, n = this.children.size; i < n; i++)
((N)children[i]).removeFromTree(tree, actorIndex);
}
tree.invalidateHierarchy();
}

/** Called to add the actor to the tree when the node's parent is expanded. */
protected void addToTree (Tree<N, V> tree) {
tree.addActor(actor);
if (!expanded) return;
/** Called to add the actor to the tree when the node's parent is expanded.
* @return The number of node actors added to the tree. */
protected int addToTree (Tree<N, V> tree, int actorIndex) {
tree.addActorAt(actorIndex, actor);
if (!expanded) return 1;
int added = 1;
Object[] children = this.children.items;
for (int i = this.children.size - 1; i >= 0; i--)
((N)children[i]).addToTree(tree);
for (int i = 0, n = this.children.size; i < n; i++)
added += ((N)children[i]).addToTree(tree, actorIndex + added);
return added;
}

/** Called to remove the actor from the tree when the node's parent is collapsed. */
protected void removeFromTree (Tree<N, V> tree) {
tree.removeActor(actor);
protected void removeFromTree (Tree<N, V> tree, int actorIndex) {
Actor removeActorAt = tree.removeActorAt(actorIndex, true);
if (!expanded) return;
Object[] children = this.children.items;
for (int i = this.children.size - 1; i >= 0; i--)
((N)children[i]).removeFromTree(tree);
for (int i = 0, n = this.children.size; i < n; i++)
((N)children[i]).removeFromTree(tree, actorIndex);
}

public void add (N node) {
Expand All @@ -610,12 +619,35 @@ public void addAll (Array<N> nodes) {
insert(children.size, nodes.get(i));
}

public void insert (int index, N node) {
public void insert (int childIndex, N node) {
node.parent = this;
children.insert(index, node);
updateChildren();
children.insert(childIndex, node);
if (!expanded) return;
Tree tree = getTree();
if (tree != null) {
int actorIndex;
if (childIndex == 0)
actorIndex = actor.getZIndex() + 1;
else if (childIndex < children.size - 1)
actorIndex = children.get(childIndex + 1).actor.getZIndex();
else {
N before = children.get(childIndex - 1);
actorIndex = before.actor.getZIndex() + before.countActors();
}
node.addToTree(tree, actorIndex);
}
}

int countActors () {
if (!expanded) return 1;
int count = 1;
Object[] children = this.children.items;
for (int i = 0, n = this.children.size; i < n; i++)
count += ((N)children[i]).countActors();
return count;
}

/** Remove this node from the tree. */
public void remove () {
Tree tree = getTree();
if (tree != null)
Expand All @@ -624,19 +656,24 @@ else if (parent != null) //
parent.remove(this);
}

/** Remove the specified child node from the tree. */
public void remove (N node) {
children.removeValue(node, true);
if (!children.removeValue(node, true)) return;
if (!expanded) return;
Tree tree = getTree();
if (tree != null) node.removeFromTree(tree);
if (tree != null) node.removeFromTree(tree, node.actor.getZIndex());
}

/** Remove all child nodes from the tree. */
public void removeAll () {
Tree tree = getTree();
if (tree != null) {
Object[] children = this.children.items;
for (int i = this.children.size - 1; i >= 0; i--)
((N)children[i]).removeFromTree(tree);
if (expanded) {
Tree tree = getTree();
if (tree != null) {
int actorIndex = actor.getZIndex() + 1;
Object[] children = this.children.items;
for (int i = 0, n = this.children.size; i < n; i++)
((N)children[i]).removeFromTree(tree, actorIndex);
}
}
children.clear();
}
Expand Down Expand Up @@ -684,10 +721,13 @@ public void updateChildren () {
if (!expanded) return;
Tree tree = getTree();
if (tree == null) return;
for (int i = children.size - 1; i >= 0; i--)
children.get(i).removeFromTree(tree);
for (int i = 0, n = children.size; i < n; i++)
children.get(i).addToTree(tree);
Object[] children = this.children.items;
int n = this.children.size;
int actorIndex = actor.getZIndex() + 1;
for (int i = 0; i < n; i++)
((N)children[i]).removeFromTree(tree, actorIndex);
for (int i = 0; i < n; i++)
actorIndex += ((N)children[i]).addToTree(tree, actorIndex);
}

/** @return May be null. */
Expand Down

0 comments on commit 78ec523

Please sign in to comment.