diff --git a/src/mcedit2/rendering/scenegraph/rendernode.py b/src/mcedit2/rendering/scenegraph/rendernode.py index 278e6dc..75febc2 100644 --- a/src/mcedit2/rendering/scenegraph/rendernode.py +++ b/src/mcedit2/rendering/scenegraph/rendernode.py @@ -152,8 +152,34 @@ class BoxFaceRenderNode(RenderNode): GL.glDisable(GL.GL_BLEND) """ +def createRenderNode(sceneNode): + """ + Create and return a renderNode that renders the given sceneNode and all of its + children. + + Calls updateRenderNode to recursively create child renderNodes for each descendent of + sceneNode. + + :type sceneNode: Node + :rtype: mcedit2.rendering.rendernode.RenderNode + """ + renderNode = sceneNode.RenderNodeClass(sceneNode) + updateRenderNode(renderNode) + return renderNode + + def updateRenderNode(renderNode): """ + Synchronize the state of a renderNode and its childre with its scene node. + + If the sceneNode that owns this renderNode is dirty, invalidates the renderNode. + Then, updateChildren is called to add or remove renderNodes if the sceneNode had + children added or removed. + + As an optimization, each sceneNode keeps track of whether one of its descendents + was dirtied or had children added or removed. This allows us to skip the recursive + updateRenderNode call if it is not needed. + :type renderNode: mcedit2.rendering.rendernode.RenderNode """ @@ -162,47 +188,45 @@ def updateRenderNode(renderNode): if sceneNode.dirty: renderNode.invalidate() sceneNode.dirty = False - if sceneNode.descendentChildrenChanged or sceneNode.childrenChanged: + + if sceneNode.childrenChanged: updateChildren(renderNode) - sceneNode.descendentChildrenChanged = False sceneNode.childrenChanged = False - -def createRenderNode(sceneNode): - """ - - :type sceneNode: Node - :rtype: mcedit2.rendering.rendernode.RenderNode - """ - renderNode = sceneNode.RenderNodeClass(sceneNode) - updateChildren(renderNode) - return renderNode - + if sceneNode.descendentNeedsUpdate: + for renderChild in renderNode.children: + updateRenderNode(renderChild) + sceneNode.descendentNeedsUpdate = False def updateChildren(renderNode): """ + Compare the children of this renderNode to the children of its sceneNode. Create + renderNodes for any new sceneNodes, and remove any renderNodes whose + sceneNode is no longer a child of this node's sceneNode. :type renderNode: mcedit2.rendering.rendernode.RenderNode :return: :rtype: """ sceneNode = renderNode.sceneNode - deadChildren = [] + orphans = [] + + # Find renderNode children whose sceneNode no longer has a parent for renderChild in renderNode.children: if renderChild.sceneNode.parent is None: - deadChildren.append(renderChild) + orphans.append(renderChild) - for dc in deadChildren: - renderNode.removeChild(dc) - dc.destroy() + for node in orphans: + renderNode.removeChild(node) + node.destroy() + # Find sceneNode children who do not have a renderNode as a child of this renderNode for index, sceneChild in enumerate(sceneNode.children): renderChild = renderNode.childrenBySceneNode.get(sceneChild) if renderChild is None: renderNode.insertNode(index, createRenderNode(sceneChild)) sceneChild.dirty = False - else: - updateRenderNode(renderChild) + def renderScene(renderNode): diff --git a/src/mcedit2/rendering/scenegraph/scenenode.py b/src/mcedit2/rendering/scenegraph/scenenode.py index 9b2b2bb..8197339 100644 --- a/src/mcedit2/rendering/scenegraph/scenenode.py +++ b/src/mcedit2/rendering/scenegraph/scenenode.py @@ -18,7 +18,7 @@ class Node(object): self._children = [] self._dirty = True self.childrenChanged = False - self.descendentChildrenChanged = False + self.descendentNeedsUpdate = False def __repr__(self): return "%s(visible=%s, children=%d)" % (self.__class__.__name__, self.visible, len(self._children)) @@ -36,32 +36,32 @@ class Node(object): else: self._parent = None - def touchChildren(self): + def childrenDidChange(self): node = self node.childrenChanged = True while node.parent: node = node.parent - node.descendentChildrenChanged = True + node.descendentNeedsUpdate = True def addChild(self, node): self._children.append(node) node.parent = self - self.touchChildren() + self.childrenDidChange() def insertChild(self, index, node): self._children.insert(index, node) node.parent = self - self.touchChildren() + self.childrenDidChange() def removeChild(self, node): self._children.remove(node) node.parent = None - self.touchChildren() + self.childrenDidChange() def clear(self): for c in self._children: c.parent = None - self.touchChildren() + self.childrenDidChange() self._children[:] = [] def childCount(self): @@ -82,7 +82,7 @@ class Node(object): node = self while node.parent: node = node.parent - node.descendentChildrenChanged = True + node.descendentNeedsUpdate = True _visible = True @property @@ -111,7 +111,7 @@ class NamedChildrenNode(Node): oldNode.parent = None self._children[name] = node node.parent = self - self.touchChildren() + self.childrenDidChange() insertChild = NotImplemented @@ -119,7 +119,7 @@ class NamedChildrenNode(Node): node = self._children.pop(name, None) if node: node.parent = None - self.touchChildren() + self.childrenDidChange() def getChild(self, name): return self._children.get(name) @@ -128,7 +128,7 @@ class NamedChildrenNode(Node): for node in self.children: node.parent = None self._children.clear() - self.touchChildren() + self.childrenDidChange() @property def children(self):