Document createRenderNode, updateRenderNode, and updateChildren to make intentions more clear.

Change updateChildren to be non-recursive.
updateRenderNode now descends into children and calls updateChildren as needed.

The rendergraph is now slightly less creepy.
This commit is contained in:
David Vierra 2015-07-19 03:06:18 -10:00
parent f66e2a8dbf
commit 5125fdf86e
2 changed files with 55 additions and 31 deletions

View File

@ -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):

View File

@ -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):