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) 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): 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 :type renderNode: mcedit2.rendering.rendernode.RenderNode
""" """
@ -162,47 +188,45 @@ def updateRenderNode(renderNode):
if sceneNode.dirty: if sceneNode.dirty:
renderNode.invalidate() renderNode.invalidate()
sceneNode.dirty = False sceneNode.dirty = False
if sceneNode.descendentChildrenChanged or sceneNode.childrenChanged:
if sceneNode.childrenChanged:
updateChildren(renderNode) updateChildren(renderNode)
sceneNode.descendentChildrenChanged = False
sceneNode.childrenChanged = False sceneNode.childrenChanged = False
if sceneNode.descendentNeedsUpdate:
def createRenderNode(sceneNode): for renderChild in renderNode.children:
""" updateRenderNode(renderChild)
sceneNode.descendentNeedsUpdate = False
:type sceneNode: Node
:rtype: mcedit2.rendering.rendernode.RenderNode
"""
renderNode = sceneNode.RenderNodeClass(sceneNode)
updateChildren(renderNode)
return renderNode
def updateChildren(renderNode): 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 :type renderNode: mcedit2.rendering.rendernode.RenderNode
:return: :return:
:rtype: :rtype:
""" """
sceneNode = renderNode.sceneNode sceneNode = renderNode.sceneNode
deadChildren = [] orphans = []
# Find renderNode children whose sceneNode no longer has a parent
for renderChild in renderNode.children: for renderChild in renderNode.children:
if renderChild.sceneNode.parent is None: if renderChild.sceneNode.parent is None:
deadChildren.append(renderChild) orphans.append(renderChild)
for dc in deadChildren: for node in orphans:
renderNode.removeChild(dc) renderNode.removeChild(node)
dc.destroy() node.destroy()
# Find sceneNode children who do not have a renderNode as a child of this renderNode
for index, sceneChild in enumerate(sceneNode.children): for index, sceneChild in enumerate(sceneNode.children):
renderChild = renderNode.childrenBySceneNode.get(sceneChild) renderChild = renderNode.childrenBySceneNode.get(sceneChild)
if renderChild is None: if renderChild is None:
renderNode.insertNode(index, createRenderNode(sceneChild)) renderNode.insertNode(index, createRenderNode(sceneChild))
sceneChild.dirty = False sceneChild.dirty = False
else:
updateRenderNode(renderChild)
def renderScene(renderNode): def renderScene(renderNode):

View File

@ -18,7 +18,7 @@ class Node(object):
self._children = [] self._children = []
self._dirty = True self._dirty = True
self.childrenChanged = False self.childrenChanged = False
self.descendentChildrenChanged = False self.descendentNeedsUpdate = False
def __repr__(self): def __repr__(self):
return "%s(visible=%s, children=%d)" % (self.__class__.__name__, self.visible, len(self._children)) return "%s(visible=%s, children=%d)" % (self.__class__.__name__, self.visible, len(self._children))
@ -36,32 +36,32 @@ class Node(object):
else: else:
self._parent = None self._parent = None
def touchChildren(self): def childrenDidChange(self):
node = self node = self
node.childrenChanged = True node.childrenChanged = True
while node.parent: while node.parent:
node = node.parent node = node.parent
node.descendentChildrenChanged = True node.descendentNeedsUpdate = True
def addChild(self, node): def addChild(self, node):
self._children.append(node) self._children.append(node)
node.parent = self node.parent = self
self.touchChildren() self.childrenDidChange()
def insertChild(self, index, node): def insertChild(self, index, node):
self._children.insert(index, node) self._children.insert(index, node)
node.parent = self node.parent = self
self.touchChildren() self.childrenDidChange()
def removeChild(self, node): def removeChild(self, node):
self._children.remove(node) self._children.remove(node)
node.parent = None node.parent = None
self.touchChildren() self.childrenDidChange()
def clear(self): def clear(self):
for c in self._children: for c in self._children:
c.parent = None c.parent = None
self.touchChildren() self.childrenDidChange()
self._children[:] = [] self._children[:] = []
def childCount(self): def childCount(self):
@ -82,7 +82,7 @@ class Node(object):
node = self node = self
while node.parent: while node.parent:
node = node.parent node = node.parent
node.descendentChildrenChanged = True node.descendentNeedsUpdate = True
_visible = True _visible = True
@property @property
@ -111,7 +111,7 @@ class NamedChildrenNode(Node):
oldNode.parent = None oldNode.parent = None
self._children[name] = node self._children[name] = node
node.parent = self node.parent = self
self.touchChildren() self.childrenDidChange()
insertChild = NotImplemented insertChild = NotImplemented
@ -119,7 +119,7 @@ class NamedChildrenNode(Node):
node = self._children.pop(name, None) node = self._children.pop(name, None)
if node: if node:
node.parent = None node.parent = None
self.touchChildren() self.childrenDidChange()
def getChild(self, name): def getChild(self, name):
return self._children.get(name) return self._children.get(name)
@ -128,7 +128,7 @@ class NamedChildrenNode(Node):
for node in self.children: for node in self.children:
node.parent = None node.parent = None
self._children.clear() self._children.clear()
self.touchChildren() self.childrenDidChange()
@property @property
def children(self): def children(self):