# mcedit2.rendering.rendergraph — mceditlib 0.1 documentation

### Navigation

- index
- modules |
- mceditlib 0.1 documentation »
- Module code »

# Source code for mcedit2.rendering.rendergraph

    """
        ${NAME}
    """
    from __future__ import absolute_import, division, print_function
    import collections
    import logging
    import weakref
    from OpenGL import GL
    import numpy
    from mcedit2.rendering import cubes
    from mcedit2.rendering.depths import DepthOffset
    from mcedit2.util import profiler
    from mcedit2.util.glutils import DisplayList, gl

    log = logging.getLogger(__name__)

    class RenderNode(object):

        def __init__(self, sceneNode):
            super(RenderNode, self).__init__()
            self.children = []
            self.childrenBySceneNode = {}
            self.sceneNode = sceneNode
            self.displayList = DisplayList()          # Recompiled whenever this node's scenegraph node is dirty
                                                      # or node gains or loses children
            self.childNeedsRecompile = True

        def __repr__(self):
            return "%s(%s)" % (self.__class__.__name__, self.sceneNode)

        _parent = None
        @property
        def parent(self):
            if self._parent:
                return self._parent()

        @parent.setter
        def parent(self, value):
            if value:
                self._parent = weakref.ref(value)
            else:
                self._parent = value

        def addChild(self, node):
            self.children.append(node)
            self._addChild(node)

        def _addChild(self, node):
            self.childrenBySceneNode[node.sceneNode] = node
            node.parent = self
            self.displayList.invalidate()
            self.childNeedsRecompile = True
            if self.parent:
                self.parent.touch()

        def insertNode(self, index, node):
            self.children.insert(index, node)
            self._addChild(node)

        def removeChild(self, node):
            self.childrenBySceneNode.pop(node.sceneNode, None)
            self.children.remove(node)
            self.displayList.invalidate()
            node.parent = None
            self.childNeedsRecompile = True
            if self.parent:
                self.parent.touch()

        def invalidate(self):
            self.displayList.invalidate()
            self.touch()

        def touch(self):
            node = self
            while node:
                node.childNeedsRecompile = True
                node = node.parent

        def getList(self):
            return self.displayList.getList()

        def callList(self):
            self.displayList.call()

        def compile(self):
            if self.childNeedsRecompile:
                for node in self.children:
                    if node.sceneNode.visible:
                        node.compile()
                self.childNeedsRecompile = False

            self.displayList.compile(self.draw)

        def draw(self):
            self.drawSelf()
            self.drawChildren()

        def drawChildren(self):
            if len(self.children):
                lists = [node.getList()
                         for node in self.children
                         if node.sceneNode.visible]
                if len(lists):
                    lists = numpy.hstack(tuple(lists))
                    try:
                        GL.glCallLists(lists)
                    except GL.error as e:
                        log.exception("Error calling child lists: %s", e)
                        raise

        def drawSelf(self):
            pass

        def destroyLists(self):
            for child in self.children:
                child.destroyLists()
            self.displayList.destroy()

    class RenderstateRenderNode(RenderNode):
        def draw(self):
            self.enter()
            self.drawChildren()
            self.exit()

        def enter(self):
            raise NotImplementedError

        def exit(self):
            raise NotImplementedError

    class TextureAtlasRenderNode(RenderstateRenderNode):
        def __init__(self, sceneNode):
            super(TextureAtlasRenderNode, self).__init__(sceneNode)
            self.textureAtlas = sceneNode.textureAtlas

        def compile(self):
            self.textureAtlas.load()
            super(TextureAtlasRenderNode, self).compile()

        def enter(self):
            GL.glColor(1., 1., 1., 1.)
            textureAtlas = self.textureAtlas
            GL.glActiveTexture(GL.GL_TEXTURE0)
            GL.glEnable(GL.GL_TEXTURE_2D)
            textureAtlas.bindTerrain()

            GL.glMatrixMode(GL.GL_TEXTURE)
            GL.glPushMatrix()
            GL.glLoadIdentity()
            GL.glScale(1. / textureAtlas.width, 1. / textureAtlas.height, 1.)

            GL.glActiveTexture(GL.GL_TEXTURE1)
            GL.glEnable(GL.GL_TEXTURE_2D)
            textureAtlas.bindLight()

            GL.glMatrixMode(GL.GL_TEXTURE)
            GL.glPushMatrix()
            GL.glLoadIdentity()
            GL.glScale(1. / 16, 1. / 16, 1.)

            GL.glActiveTexture(GL.GL_TEXTURE0)
            GL.glEnable(GL.GL_CULL_FACE)

        def exit(self):
            GL.glDisable(GL.GL_CULL_FACE)
            GL.glActiveTexture(GL.GL_TEXTURE1)
            GL.glBindTexture(GL.GL_TEXTURE_2D, 0)
            GL.glDisable(GL.GL_TEXTURE_2D)
            GL.glMatrixMode(GL.GL_TEXTURE)
            GL.glPopMatrix()

            GL.glActiveTexture(GL.GL_TEXTURE0)
            GL.glDisable(GL.GL_TEXTURE_2D)
            GL.glMatrixMode(GL.GL_TEXTURE)
            GL.glPopMatrix()

    class TranslateRenderNode(RenderstateRenderNode):
        def __init__(self, sceneNode):
            """

            :type sceneNode: TranslateNode
            """
            super(TranslateRenderNode, self).__init__(sceneNode)

        def __repr__(self):
            return "TranslateRenderNode(%s)" % (self.sceneNode.translateOffset,)

        def enter(self):
            GL.glMatrixMode(GL.GL_MODELVIEW)
            GL.glPushMatrix()
            GL.glTranslate(*self.sceneNode.translateOffset)

        def exit(self):
            GL.glMatrixMode(GL.GL_MODELVIEW)
            GL.glPopMatrix()

    class VertexRenderNode(RenderNode):
        def __init__(self, sceneNode):
            """

            :type sceneNode: VertexNode
            """
            super(VertexRenderNode, self).__init__(sceneNode)

            self.didDraw = False

        def invalidate(self):
            if self.didDraw:
                assert False
            super(VertexRenderNode, self).invalidate()

        def drawSelf(self):
            self.didDraw = True
            bare = []
            withTex = []
            withLights = []
            for array in self.sceneNode.vertexArrays:
                if array.lights:
                    withLights.append(array)
                elif array.textures:
                    withTex.append(array)
                else:
                    bare.append(array)

            with gl.glPushAttrib(GL.GL_ENABLE_BIT):
                GL.glDisable(GL.GL_TEXTURE_2D)
                self.drawArrays(bare, False, False)
                GL.glEnable(GL.GL_TEXTURE_2D)
                self.drawArrays(withTex, True, False)
                self.drawArrays(withLights, True, True)

        def drawArrays(self, vertexArrays, textures, lights):
            if textures:
                GL.glClientActiveTexture(GL.GL_TEXTURE0)
                GL.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY)
            if lights:
                GL.glClientActiveTexture(GL.GL_TEXTURE1)
                GL.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY)
            else:
                GL.glMultiTexCoord2d(GL.GL_TEXTURE1, 15, 15)

            GL.glEnableClientState(GL.GL_COLOR_ARRAY)

            for array in vertexArrays:
                if 0 == len(array.buffer):
                    continue
                stride = 4 * array.elements

                buf = array.buffer.ravel()

                GL.glVertexPointer(3, GL.GL_FLOAT, stride, buf)
                if textures:
                    GL.glClientActiveTexture(GL.GL_TEXTURE0)
                    GL.glTexCoordPointer(2, GL.GL_FLOAT, stride, (buf[array.texOffset:]))
                if lights:
                    GL.glClientActiveTexture(GL.GL_TEXTURE1)
                    GL.glTexCoordPointer(2, GL.GL_FLOAT, stride, (buf[array.lightOffset:]))
                GL.glColorPointer(4, GL.GL_UNSIGNED_BYTE, stride, (buf.view(dtype=numpy.uint8)[array.rgbaOffset*4:]))

                vertexCount = int(array.buffer.size / array.elements)
                GL.glDrawArrays(array.gl_type, 0, vertexCount)

            GL.glDisableClientState(GL.GL_COLOR_ARRAY)

            if lights:
                GL.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY)

            if textures:
                GL.glClientActiveTexture(GL.GL_TEXTURE0)
                GL.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY)

    class OrthoRenderNode(RenderstateRenderNode):
        def enter(self):
            w, h = self.sceneNode.size
            GL.glMatrixMode(GL.GL_PROJECTION)
            GL.glPushMatrix()
            GL.glLoadIdentity()
            GL.glOrtho(0., w, 0., h, -200, 200)

        def exit(self):
            GL.glMatrixMode(GL.GL_PROJECTION)
            GL.glPopMatrix()

    class ClearRenderNode(RenderNode):
        def drawSelf(self):
            color = self.sceneNode.clearColor
            if color is None:
                GL.glClear(GL.GL_DEPTH_BUFFER_BIT)
            else:
                GL.glClearColor(*color)
                GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

    class DepthMaskRenderNode(RenderstateRenderNode):
        def enter(self):
            GL.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT)
            GL.glDepthMask(self.sceneNode.mask)

        def exit(self):
            GL.glPopAttrib()

    class BoxRenderNode(RenderNode):
        def drawSelf(self):
            box = self.sceneNode.box
            color = self.sceneNode.color
            GL.glPolygonOffset(DepthOffset.Selection, DepthOffset.Selection)
            cubes.drawConstructionCube(box, color)

    class BoxFaceRenderNode(RenderNode):
        def drawBoxFace(self, box, face, color=(0.9, 0.6, 0.2, 0.5)):
            GL.glEnable(GL.GL_BLEND)
            GL.glColor(*color)
            cubes.drawFace(box, face)

            GL.glColor(0.9, 0.6, 0.2, 0.8)
            GL.glLineWidth(2.0)
            cubes.drawFace(box, face, elementType=GL.GL_LINE_STRIP)
            GL.glDisable(GL.GL_BLEND)

    class DepthOffsetRenderNode(RenderstateRenderNode):
        def enter(self):
            GL.glPushAttrib(GL.GL_POLYGON_BIT)
            GL.glPolygonOffset(self.sceneNode.depthOffset, self.sceneNode.depthOffset)
            GL.glEnable(GL.GL_POLYGON_OFFSET_FILL)

        def exit(self):
            GL.glPopAttrib()

    def updateRenderNode(renderNode):
        """

        :type renderNode: mcedit2.rendering.rendergraph.RenderNode
        """
        sceneNode = renderNode.sceneNode

        if sceneNode.dirty:
            renderNode.invalidate()
            sceneNode.dirty = False
        if sceneNode.descendentChildrenChanged or sceneNode.childrenChanged:
            updateChildren(renderNode)
            sceneNode.descendentChildrenChanged = False
            sceneNode.childrenChanged = False

    def createRenderNode(sceneNode):
        """

        :type sceneNode: Node
        :rtype: mcedit2.rendering.rendergraph.RenderNode
        """
        renderNode = sceneNode.RenderNodeClass(sceneNode)
        updateChildren(renderNode)
        return renderNode

    def updateChildren(renderNode):
        """

        :type renderNode: mcedit2.rendering.rendergraph.RenderNode
        :return:
        :rtype:
        """
        sceneNode = renderNode.sceneNode
        deadChildren = []
        for renderChild in renderNode.children:
            if renderChild.sceneNode.parent is None:
                deadChildren.append(renderChild)

        for dc in deadChildren:
            renderNode.removeChild(dc)
            dc.destroyLists()

        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):
        with profiler.context("updateRenderNode"):
            updateRenderNode(renderNode)
        with profiler.context("renderNode.compile"):
            renderNode.compile()
        with profiler.context("renderNode.callList"):
            renderNode.callList()

### Navigation

- index
- modules |
- mceditlib 0.1 documentation »
- Module code »