def __init__(self): """ :return: :rtype: """ super(SelectionScene, self).__init__() self.cullNode = RenderstateNode(CullFaceRenderNode) self.blendNode = RenderstateNode(_RenderstateAlphaBlendNode) self.groupNode = ChunkGroupNode() self.cullNode.addChild(self.blendNode) self.blendNode.addChild(self.groupNode) self.addChild(self.cullNode) self.loadTimer = QtCore.QTimer(timeout=self.loadMore) self.loadTimer.setInterval(0) self.loadTimer.start() self.renderSelection = None
class SelectionScene(scenegraph.Node): def __init__(self): """ :return: :rtype: """ super(SelectionScene, self).__init__() self.cullNode = RenderstateNode(CullFaceRenderNode) self.blendNode = RenderstateNode(_RenderstateAlphaBlendNode) self.groupNode = ChunkGroupNode() self.cullNode.addChild(self.blendNode) self.blendNode.addChild(self.groupNode) self.addChild(self.cullNode) self.loadTimer = QtCore.QTimer(timeout=self.loadMore) self.loadTimer.setInterval(0) self.loadTimer.start() self.renderSelection = None def __del__(self): self.loadTimer.stop() _selection = None @property def selection(self): return self._selection @selection.setter def selection(self, selection): if selection != self._selection: self._selection = selection self.updateSelection() _dimension = None @property def dimension(self): return self._dimension @dimension.setter def dimension(self, value): if value != self._dimension: self._dimension = value self.updateSelection() @property def filled(self): return self.cullNode.visible @filled.setter def filled(self, value): self.cullNode.visible = value def updateSelection(self): if self.dimension is None or self.selection is None: return selection = self.selection self.renderSelection = selection & NonAirMaskSelection(self.dimension, selection) self.groupNode.clear() self._loader = None if selection.chunkCount < 16: exhaust(self.loadSections()) self.loadTimer.setInterval(333) _loader = None def loadMore(self): if self._loader is None: self._loader = self.loadSections() try: self._loader.next() except StopIteration: self._loader = None @profiler.iterator("SelectionScene") def loadSections(self): selection = self.renderSelection if selection is None: self.loadTimer.setInterval(333) return else: self.loadTimer.setInterval(0) for cx, cz in selection.chunkPositions(): if self.groupNode.containsChunkNode((cx, cz)): continue vertexArrays = [] for cy in selection.sectionPositions(cx, cz): box = SectionBox(cx, cy, cz).expand(1) mask = selection.box_mask(box) if mask is not None: vertexArrays.extend(self.buildSection(mask, cy)) if len(vertexArrays): chunkNode = ChunkNode((cx, cz)) vertexNode = VertexNode(vertexArrays) chunkNode.addChild(vertexNode) self.groupNode.addChunkNode(chunkNode) yield self.loadTimer.setInterval(333) def discardChunk(self, cx, cz): self.groupNode.discardChunkNode(cx, cz) def exposedBlockMasks(self, mask): """ Compare adjacent cells in the 3d mask along all three axes and return one mask for each cardinal direction. The returned masks contain the faces of each cell which are exposed in that direction and should be rendered. :param mask: :type mask: ndarray :return: :rtype: list[ndarray] """ sy = sz = sx = 16 exposedY = numpy.zeros((sy+1, sz, sx), dtype=bool) exposedZ = numpy.zeros((sy, sz+1, sx), dtype=bool) exposedX = numpy.zeros((sy, sz, sx+1), dtype=bool) exposedY[:] = mask[1:, 1:-1, 1:-1] != mask[ :-1, 1:-1, 1:-1] exposedZ[:] = mask[1:-1, 1:, 1:-1] != mask[1:-1, :-1, 1:-1] exposedX[:] = mask[1:-1, 1:-1, 1: ] != mask[1:-1, 1:-1, :-1] exposedByFace = [ exposedX[:, :, 1:], exposedX[:, :, :-1], exposedY[1:], exposedY[:-1], exposedZ[:, 1:], exposedZ[:, :-1], ] return exposedByFace def buildSection(self, sectionMask, cy): vertexArrays = [] for (face, exposedFaceMask) in enumerate(self.exposedBlockMasks(sectionMask)): blockMask = sectionMask[1:-1, 1:-1, 1:-1] & exposedFaceMask vertexBuffer = QuadVertexArrayBuffer.fromBlockMask(face, blockMask, False, False) if not len(vertexBuffer.vertex): continue vertexBuffer.rgb[:] = faceShades[face] vertexBuffer.alpha[:] = 0x77 vertexBuffer.vertex[..., 1] += cy << 4 vertexArrays.append(vertexBuffer) return vertexArrays
class SelectionScene(scenegraph.Node): def __init__(self): """ :return: :rtype: """ super(SelectionScene, self).__init__() self.cullNode = RenderstateNode(CullFaceRenderNode) self.blendNode = RenderstateNode(_RenderstateAlphaBlendNode) self.groupNode = ChunkGroupNode() self.cullNode.addChild(self.blendNode) self.blendNode.addChild(self.groupNode) self.addChild(self.cullNode) self.loadTimer = QtCore.QTimer(timeout=self.loadMore) self.loadTimer.setInterval(0) self.loadTimer.start() self.renderSelection = None def __del__(self): self.loadTimer.stop() _selection = None @property def selection(self): return self._selection @selection.setter def selection(self, selection): if selection != self._selection: self._selection = selection self.updateSelection() _dimension = None @property def dimension(self): return self._dimension @dimension.setter def dimension(self, value): if value != self._dimension: self._dimension = value self.updateSelection() @property def filled(self): return self.cullNode.visible @filled.setter def filled(self, value): self.cullNode.visible = value def updateSelection(self): if self.dimension is None or self.selection is None: return selection = self.selection self.renderSelection = selection & NonAirMaskSelection(self.dimension, selection) self.groupNode.clear() self._loader = None if selection.chunkCount < 16: for _ in self.loadSections(): pass self.loadTimer.setInterval(333) _loader = None def loadMore(self): if self._loader is None: self._loader = self.loadSections() try: self._loader.next() except StopIteration: self._loader = None @profiler.iterator("SelectionScene") def loadSections(self): selection = self.renderSelection if selection is None: self.loadTimer.setInterval(333) return else: self.loadTimer.setInterval(0) for cx, cz in selection.chunkPositions(): if self.groupNode.containsChunkNode((cx, cz)): continue vertexArrays = [] for cy in selection.sectionPositions(cx, cz): box = SectionBox(cx, cy, cz).expand(1) mask = selection.box_mask(box) if mask is not None: vertexArrays.extend(self.buildSection(mask, cy)) if len(vertexArrays): chunkNode = ChunkNode((cx, cz)) vertexNode = VertexNode(vertexArrays) chunkNode.addChild(vertexNode) self.groupNode.addChunkNode(chunkNode) yield self.loadTimer.setInterval(333) def exposedBlockMasks(self, mask): """ Compare adjacent cells in the 3d mask along all three axes and return one mask for each cardinal direction. The returned masks contain the faces of each cell which are exposed in that direction and should be rendered. :param mask: :type mask: ndarray :return: :rtype: list[ndarray] """ sy = sz = sx = 16 exposedY = numpy.zeros((sy+1, sz, sx), dtype=bool) exposedZ = numpy.zeros((sy, sz+1, sx), dtype=bool) exposedX = numpy.zeros((sy, sz, sx+1), dtype=bool) exposedY[:] = mask[1:, 1:-1, 1:-1] != mask[ :-1, 1:-1, 1:-1] exposedZ[:] = mask[1:-1, 1:, 1:-1] != mask[1:-1, :-1, 1:-1] exposedX[:] = mask[1:-1, 1:-1, 1: ] != mask[1:-1, 1:-1, :-1] exposedByFace = [ exposedX[:, :, 1:], exposedX[:, :, :-1], exposedY[1:], exposedY[:-1], exposedZ[:, 1:], exposedZ[:, :-1], ] return exposedByFace def buildSection(self, sectionMask, cy): vertexArrays = [] for (face, exposedFaceMask) in enumerate(self.exposedBlockMasks(sectionMask)): blockIndices = sectionMask[1:-1, 1:-1, 1:-1] & exposedFaceMask vertexBuffer = VertexArrayBuffer.fromIndices(face, blockIndices, False, False) if not len(vertexBuffer.vertex): continue vertexBuffer.rgb[:] = faceShades[face] vertexBuffer.alpha[:] = 0x77 vertexBuffer.vertex[..., 1] += cy << 4 vertexArrays.append(vertexBuffer) return vertexArrays