示例#1
0
    def centerOnPoint(self, pos, distance=None):
        #self.rotateView(45., math.degrees(math.atan(1/math.sqrt(2))))
        vec = self.cameraVector()
        ray = Ray(pos, -vec)
        newPos = ray.atHeight(self.hoverHeight)

        log.info("Iso: centering on %s (moving to %s)", pos, newPos)
        self.centerPoint = newPos
示例#2
0
    def centerOnPoint(self, pos, distance=None):
        #self.rotateView(45., math.degrees(math.atan(1/math.sqrt(2))))
        vec = self.cameraVector()
        ray = Ray(pos, -vec)
        newPos = ray.atHeight(self.hoverHeight)

        log.info("Iso: centering on %s (moving to %s)", pos, newPos)
        self.centerPoint = newPos
示例#3
0
    def drawSelf(self):
        if self.sceneNode.corners is None or self.sceneNode.dimension is None:
            return
        corners = self.sceneNode.corners

        outwardSegments = [
            LineSegment(corners[i], corners[j]) for i, j in self.outwardIndices
        ]
        verticalSegments = [
            LineSegment(corners[i], corners[j])
            for i, j in self.verticalIndices
        ]
        points = []

        for segment in outwardSegments:
            p = segment.atHeight(self.sceneNode.planeHeight)
            if p is not None:
                points.append(p)

        if len(points) < 4:
            # only intersected two outward segments. check the far verticals.
            for segment in verticalSegments[:2]:
                r = Ray.fromPoints(*segment)
                points.append(r.atHeight(self.sceneNode.planeHeight))

        if len(points) < 4:
            # intersected zero outward segments!
            # rarely occurs, the near verticals are 1/10 of a block tall
            for segment in verticalSegments[2:]:
                r = Ray.fromPoints(*segment)
                points.append(r.atHeight(self.sceneNode.planeHeight))

        if len(points) < 4:
            return

        p1, p2, p3, p4 = points[:4]
        points = [p1, p2, p4, p3, p1]

        with gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT, GL.GL_COLOR_BUFFER_BIT):
            GL.glDepthMask(False)
            GL.glEnable(GL.GL_BLEND)
            GL.glVertexPointer(3, GL.GL_FLOAT, 0, numpy.array(points).ravel())

            GL.glLineWidth(3.0)

            GL.glColor(1, 1, .1, 0.5)
            GL.glDisable(GL.GL_DEPTH_TEST)
            GL.glDrawArrays(GL.GL_LINE_STRIP, 0, len(points))
示例#4
0
    def __init__(self, dimension, textureAtlas=None, geometryCache=None, sharedGLWidget=None):
        """

        :param dimension:
        :type dimension: WorldEditorDimension
        :param textureAtlas:
        :type textureAtlas: TextureAtlas
        :param geometryCache:
        :type geometryCache: GeometryCache
        :param sharedGLWidget:
        :type sharedGLWidget: QGLWidget
        :return:
        :rtype:
        """
        QGLWidget.__init__(self, shareWidget=sharedGLWidget)
        self.setSizePolicy(QtGui.QSizePolicy.Policy.Expanding, QtGui.QSizePolicy.Policy.Expanding)
        self.setFocusPolicy(Qt.ClickFocus)

        self.layerToggleGroup = LayerToggleGroup()
        self.layerToggleGroup.layerToggled.connect(self.setLayerVisible)

        self.dimension = None
        self.worldScene = None
        self.loadableChunksNode = None
        self.textureAtlas = None

        self.mouseRay = Ray(Vector(0, 1, 0), Vector(0, -1, 0))

        self.setMouseTracking(True)

        self.lastAutoUpdate = time.time()
        self.autoUpdateInterval = 0.5  # frequency of screen redraws in response to loaded chunks

        self.compassNode = self.createCompass()
        self.compassOrthoNode = scenegraph.OrthoNode((1, float(self.height()) / self.width()))
        self.compassOrthoNode.addChild(self.compassNode)

        self.viewActions = []
        self.pressedKeys = set()

        self.setTextureAtlas(textureAtlas)

        if geometryCache is None and sharedGLWidget is not None:
            geometryCache = sharedGLWidget.geometryCache
        if geometryCache is None:
            geometryCache = GeometryCache()
        self.geometryCache = geometryCache

        self.matrixNode = None
        self.overlayNode = scenegraph.Node()

        self.sceneGraph = None
        self.renderGraph = None

        self.frameSamples = deque(maxlen=500)
        self.frameSamples.append(time.time())

        self.cursorNode = None

        self.setDimension(dimension)
示例#5
0
    def atHeight(self, y):
        p1 = self.p1
        p2 = self.p2
        if not (p1.y < y < p2.y or p1.y > y > p2.y):
            return None

        r = Ray.fromPoints(p1, p2)
        return r.atHeight(y)
示例#6
0
    def atHeight(self, y):
        p1 = self.p1
        p2 = self.p2
        if not (p1.y < y < p2.y or p1.y > y > p2.y):
            return None

        r = Ray.fromPoints(p1, p2)
        return r.atHeight(y)
示例#7
0
    def drawSelf(self):
        if self.sceneNode.corners is None or self.sceneNode.dimension is None:
            return
        corners = self.sceneNode.corners

        outwardSegments = [LineSegment(corners[i], corners[j]) for i, j in self.outwardIndices]
        verticalSegments = [LineSegment(corners[i], corners[j]) for i, j in self.verticalIndices]
        points = []

        for segment in outwardSegments:
            p = segment.atHeight(self.sceneNode.planeHeight)
            if p is not None:
                points.append(p)

        if len(points) < 4:
            # only intersected two outward segments. check the far verticals.
            for segment in verticalSegments[:2]:
                r = Ray.fromPoints(*segment)
                points.append(r.atHeight(self.sceneNode.planeHeight))

        if len(points) < 4:
            # intersected zero outward segments!
            # rarely occurs, the near verticals are 1/10 of a block tall
            for segment in verticalSegments[2:]:
                r = Ray.fromPoints(*segment)
                points.append(r.atHeight(self.sceneNode.planeHeight))

        if len(points) < 4:
            return

        p1, p2, p3, p4 = points[:4]
        points = [p1, p2, p4, p3, p1]

        with gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT, GL.GL_COLOR_BUFFER_BIT):
            GL.glDepthMask(False)
            GL.glEnable(GL.GL_BLEND)
            GL.glVertexPointer(3, GL.GL_FLOAT, 0, numpy.array(points).ravel())

            GL.glLineWidth(3.0)

            GL.glColor(1, 1, .1, 0.5)
            GL.glDisable(GL.GL_DEPTH_TEST)
            GL.glDrawArrays(GL.GL_LINE_STRIP, 0, len(points))
示例#8
0
 def rayCastCorner(near, far):
     ray = Ray.fromPoints(near, far)
     if not any(ray.vector):
         return far
     try:
         #point = rayCastInBounds(ray, dimension, 50)[0]
         #return point or far
         return near + (near - far) / 4
     except raycast.MaxDistanceError:
         return ray.atHeight(0)
示例#9
0
 def rayCastCorner(near, far):
     ray = Ray.fromPoints(near, far)
     if not any(ray.vector):
         return far
     try:
         #point = rayCastInBounds(ray, dimension, 50)[0]
         #return point or far
         return near + (near - far) / 4
     except raycast.MaxDistanceError:
         return ray.atHeight(0)
示例#10
0
    def rayAtPosition(self, x, y):
        """
        Given coordinates in screen space, return a ray in 3D space.

        Parameters:
            x and y are coordinates local to this QWidget

        :rtype: Ray
        """

        p0, p1 = self.pointsAtPositions((x, y, 0.0), (x, y, 0.1))
        return Ray(p0, (p1 - p0).normalize())
示例#11
0
    def currentViewMatrixChanged(self, currentView):
        self.viewCornersNode.corners = currentView.getViewCorners()
        try:
            targetPoint, face = rayCastInBounds(Ray(currentView.centerPoint, currentView.cameraVector), self.dimension, 100)
            if targetPoint is None:
                raise MaxDistanceError
            planeHeight = targetPoint.y
            
        except MaxDistanceError:
            planeDistance = 20
            planeHeight = (currentView.centerPoint + currentView.cameraVector * planeDistance).y

        self.viewCornersNode.planeHeight = planeHeight
示例#12
0
def rayCast(ray, dimension, maxDistance=100, hitAir=False):
    """
    Borrowed from https://gamedev.stackexchange.com/questions/47362/cast-ray-to-select-block-in-voxel-game

    Updates a factor t along each axis to compute the distance from the vector origin (in units of the vector
    magnitude) to the next integer value (i.e. block edge) along that axis.

    Return the block position and face of the block touched.

    Raises MaxDistanceError if the ray exceeded the max distance without hitting any blocks, or if the ray exits or
    doesn't enter the dimension's bounds.

    :param ray:
    :type ray: Ray
    :param maxDistance:
    :type maxDistance: int
    :param dimension:
    :type dimension: mceditlib.worldeditor.WorldEditorDimension
    :return: (point, face)
    :rtype:
    """
    point, vector = ray
    if all(v == 0 for v in vector):
        raise ValueError("Cannot cast with zero direction ray.")

    bounds = dimension.bounds
    if point not in bounds:
        intersects = rayIntersectsBox(bounds, ray)
        if not intersects:
            raise RayBoundsError("Ray does not enter dimension bounds.")

        point = intersects[0][0]

    point = advanceToChunk(Ray(point, vector), dimension, maxDistance * 4)
    currentCX, currentCY, currentCZ = point.intfloor()
    currentChunk = None

    for pos, face in _cast(point, vector, maxDistance, 1):
        cx = pos[0] >> 4
        cz = pos[2] >> 4
        if cx != currentCX or cz != currentCZ:
            currentCX = cx
            currentCZ = cz
            if dimension.containsChunk(cx, cz):
                currentChunk = dimension.getChunk(
                    cx, cz)  # xxxx WorldEditor.recentlyLoadedChunks
        ID = dimension.getBlockID(*pos)
        if ID or hitAir:
            return Vector(*pos), faces.Face.fromVector(face)

    raise MaxDistanceError("Ray exceeded max distance.")
示例#13
0
def rayCast(ray, dimension, maxDistance=100):
    """
    Borrowed from https://gamedev.stackexchange.com/questions/47362/cast-ray-to-select-block-in-voxel-game

    Updates a factor t along each axis to compute the distance from the vector origin (in units of the vector
    magnitude) to the next integer value (i.e. block edge) along that axis.

    Return the block position and face of the block touched.

    Raises MaxDistanceError if the ray exceeded the max distance without hitting any blocks, or if the ray exits or
    doesn't enter the dimension's bounds.

    Bypasses non-air blocks until the first air block is found, and only returns when a non-air block is found after
    the first air block.

    :param ray:
    :type ray: Ray
    :param maxDistance:
    :type maxDistance: int
    :param dimension:
    :type dimension: mceditlib.worldeditor.WorldEditorDimension
    :return: (point, face)
    :rtype:
    """
    point, vector = ray
    if all(v == 0 for v in vector):
        raise ValueError("Cannot cast with zero direction ray.")

    bounds = dimension.bounds
    if point not in bounds:
        intersects = rayIntersectsBox(bounds, ray)
        if not intersects:
            raise RayBoundsError("Ray does not enter dimension bounds.")

        point = intersects[0][0]

    point = advanceToChunk(Ray(point, vector), dimension, maxDistance * 4)

    foundAir = False

    for pos, face in _cast(point, vector, maxDistance, 1):
        ID = dimension.getBlockID(*pos)

        if ID == 0:  # xxx configurable air blocks?
            foundAir = True
        if ID and foundAir:
            return Vector(*pos), faces.Face.fromVector(face)
        if pos not in bounds:
            raise RayBoundsError("Ray exited dimension bounds")

    raise MaxDistanceError("Ray exceeded max distance.")
示例#14
0
    def getViewBounds(self):
        """
        Get the corners of the viewing area, intersected with the world's bounds.
        xxx raycast to intersect with terrain height too

        :return:
        :rtype:
        """
        corners = self.getViewCorners()
        # Convert the 4 corners into rays extending from the near point, then interpolate each ray at the
        # current dimension's height limits
        pairs = []
        for i in range(0, 8, 2):
            pairs.append(corners[i:i+2])

        rays = [Ray.fromPoints(p1, p2) for p1, p2 in pairs]
        bounds = self.dimension.bounds
        pointPairs = [(r.atHeight(bounds.maxy), r.atHeight(bounds.miny)) for r in rays]

        return sum(pointPairs, ())
示例#15
0
            if c is not None: return c

    def wantsChunk(self, c):
        return any(view.wantsChunk(c) for view in self.allViews)

    def recieveChunk(self, chunk):
        for view in self.allViews:
            for _ in view.recieveChunk(chunk):
                yield

    def invalidateChunk(self, (cx, cz)):
        for view in self.allViews:
            view.invalidateChunk((cx, cz))

    mouseBlockPos = Vector(0, 0, 0)
    mouseRay = Ray(Vector(0, 1, 0), Vector(0, -1, 0))
    mouseBlockFace = mceditlib.faces.FaceYIncreasing

    viewportMoved = QtCore.Signal(object)

    @property
    def centerPoint(self):
        return self.xView.centerPoint

    @centerPoint.setter
    def centerPoint(self, value):
        pass

    def subViewMoved(self, view):
        def _moved():
            blocked = [view.blockSignals(True) for view in self.allViews]
示例#16
0
    def __init__(self,
                 dimension,
                 textureAtlas=None,
                 geometryCache=None,
                 sharedGLWidget=None):
        """

        :param dimension:
        :type dimension: WorldEditorDimension
        :param textureAtlas:
        :type textureAtlas: TextureAtlas
        :param geometryCache:
        :type geometryCache: GeometryCache
        :param sharedGLWidget:
        :type sharedGLWidget: QGLWidget
        :return:
        :rtype:
        """
        QGLWidget.__init__(self, shareWidget=sharedGLWidget)
        self.dimension = None
        self.worldScene = None
        self.loadableChunksNode = None
        self.textureAtlas = None

        validateWidgetQGLContext(self)

        self.bufferSwapDone = True

        if THREADED_BUFFER_SWAP:
            self.setAutoBufferSwap(False)
            self.bufferSwapThread = QtCore.QThread()
            self.bufferSwapper = BufferSwapper(self)
            self.bufferSwapper.moveToThread(self.bufferSwapThread)
            self.doSwapBuffers.connect(self.bufferSwapper.swap)
            self.bufferSwapThread.start()

        self.setAcceptDrops(True)
        self.setSizePolicy(QtGui.QSizePolicy.Policy.Expanding,
                           QtGui.QSizePolicy.Policy.Expanding)
        self.setFocusPolicy(Qt.ClickFocus)

        self.layerToggleGroup = LayerToggleGroup()
        self.layerToggleGroup.layerToggled.connect(self.setLayerVisible)

        self.mouseRay = Ray(Vector(0, 1, 0), Vector(0, -1, 0))

        self.setMouseTracking(True)

        self.lastAutoUpdate = time.time()
        self.autoUpdateInterval = 0.5  # frequency of screen redraws in response to loaded chunks

        self.compassNode = self.createCompass()
        self.compassOrtho = Ortho((1, float(self.height()) / self.width()))
        self.compassNode.addState(self.compassOrtho)

        self.viewActions = []
        self.pressedKeys = set()

        self.setTextureAtlas(textureAtlas)

        if geometryCache is None and sharedGLWidget is not None:
            geometryCache = sharedGLWidget.geometryCache
        if geometryCache is None:
            geometryCache = GeometryCache()
        self.geometryCache = geometryCache

        self.worldNode = None
        self.skyNode = None
        self.overlayNode = scenenode.Node("WorldView Overlay")

        self.sceneGraph = None
        self.renderGraph = None

        self.frameSamples = deque(maxlen=500)
        self.frameSamples.append(time.time())

        self.cursorNode = None

        self.setDimension(dimension)