Reorganize WorldView methods

This commit is contained in:
David Vierra 2015-11-12 12:03:39 -10:00
parent bbc3263ad7
commit 1b6d9d07fb
3 changed files with 126 additions and 111 deletions

View File

@ -21,7 +21,7 @@ from mceditlib import faces
from mceditlib.geometry import Vector from mceditlib.geometry import Vector
from mceditlib.util.lazyprop import lazyprop from mceditlib.util.lazyprop import lazyprop
from mcedit2.worldview.viewcontrols import ViewControls from mcedit2.worldview.viewcontrols import ViewControls
from mcedit2.worldview.worldview import WorldView, iterateChunks from mcedit2.worldview.worldview import WorldView, iterateChunks, anglesToVector
from mcedit2.worldview.viewaction import ViewAction from mcedit2.worldview.viewaction import ViewAction
@ -371,7 +371,7 @@ class CameraWorldView(WorldView):
@lazyprop @lazyprop
def cameraVector(self): def cameraVector(self):
return self._anglesToVector(*self.yawPitch) return anglesToVector(*self.yawPitch)
def makeChunkIter(self): def makeChunkIter(self):
radius = self.viewDistance radius = self.viewDistance

View File

@ -7,7 +7,7 @@ import math
from PySide import QtGui from PySide import QtGui
from PySide.QtCore import Qt from PySide.QtCore import Qt
from mcedit2.widgets.layout import Row, Column from mcedit2.widgets.layout import Row, Column
from mcedit2.worldview.worldview import WorldView, iterateChunks from mcedit2.worldview.worldview import WorldView, iterateChunks, anglesToVector
from mcedit2.worldview.viewaction import ViewAction, MoveViewMouseAction, ZoomWheelAction from mcedit2.worldview.viewaction import ViewAction, MoveViewMouseAction, ZoomWheelAction
from mceditlib.geometry import Ray from mceditlib.geometry import Ray
@ -75,7 +75,7 @@ class IsoWorldView(WorldView):
)) ))
def cameraVector(self): def cameraVector(self):
return self._anglesToVector(self.yrot, self.xrot) return anglesToVector(self.yrot, self.xrot)
def centerOnPoint(self, pos, distance=None): def centerOnPoint(self, pos, distance=None):
#self.rotateView(45., math.degrees(math.atan(1/math.sqrt(2)))) #self.rotateView(45., math.degrees(math.atan(1/math.sqrt(2))))

View File

@ -37,6 +37,7 @@ from mceditlib.geometry import Vector, Ray
from mceditlib.exceptions import LevelFormatError, ChunkNotPresent from mceditlib.exceptions import LevelFormatError, ChunkNotPresent
from mceditlib.util import displayName from mceditlib.util import displayName
log = logging.getLogger(__name__)
def worldMeshVertexSize(worldMesh): def worldMeshVertexSize(worldMesh):
""" """
@ -56,7 +57,18 @@ def worldMeshVertexSize(worldMesh):
return sum(bufferSizes()) return sum(bufferSizes())
log = logging.getLogger(__name__)
def anglesToVector(yaw, pitch):
def nanzero(x):
if math.isnan(x):
return 0
else:
return x
dx = -math.sin(math.radians(yaw)) * math.cos(math.radians(pitch))
dy = -math.sin(math.radians(pitch))
dz = math.cos(math.radians(yaw)) * math.cos(math.radians(pitch))
return Vector(*map(nanzero, [dx, dy, dz]))
class BufferSwapper(QtCore.QObject): class BufferSwapper(QtCore.QObject):
@ -176,31 +188,23 @@ class WorldView(QGLWidget):
self.setDimension(dimension) self.setDimension(dimension)
acceptableMimeTypes = [ def destroy(self):
MimeFormats.MapItem, self.makeCurrent()
] self.renderGraph.destroy()
self.bufferSwapThread.quit()
super(WorldView, self).destroy()
def dragEnterEvent(self, event): def __str__(self):
# xxx show drop preview as scene node try:
print("DRAG ENTER. FORMATS:\n%s" % event.mimeData().formats()) if self.dimension:
for mimeType in self.acceptableMimeTypes: dimName = displayName(self.dimension.worldEditor.filename) + ": " + self.dimension.dimName
if event.mimeData().hasFormat(mimeType): else:
event.acceptProposedAction() dimName = "None"
return except Exception as e:
if event.mimeData().hasUrls(): return "%s trying to get node name" % e
event.acceptProposedAction() return "%s(%r)" % (self.__class__.__name__, dimName)
def dropEvent(self, event): # --- Displayed world ---
mimeData = event.mimeData()
x = event.pos().x()
y = event.pos().y()
ray = self.rayAtPosition(x, y)
dropPosition, face = self.rayCastInView(ray)
if mimeData.hasFormat(MimeFormats.MapItem):
self.mapItemDropped.emit(mimeData, dropPosition, face)
elif mimeData.hasUrls:
self.urlsDropped.emit(mimeData, dropPosition, face)
def setDimension(self, dimension): def setDimension(self, dimension):
""" """
@ -230,21 +234,7 @@ class WorldView(QGLWidget):
textureAtlas.load() textureAtlas.load()
self.resetLoadOrder() self.resetLoadOrder()
def destroy(self): # --- Graph construction ---
self.makeCurrent()
self.renderGraph.destroy()
self.bufferSwapThread.quit()
super(WorldView, self).destroy()
def __str__(self):
try:
if self.dimension:
dimName = displayName(self.dimension.worldEditor.filename) + ": " + self.dimension.dimName
else:
dimName = "None"
except Exception as e:
return "%s trying to get node name" % e
return "%s(%r)" % (self.__class__.__name__, dimName)
def createCompass(self): def createCompass(self):
return compass.CompassNode() return compass.CompassNode()
@ -279,11 +269,7 @@ class WorldView(QGLWidget):
return sceneGraph return sceneGraph
def initializeGL(self, *args, **kwargs): # --- Tool support ---
GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
GL.glAlphaFunc(GL.GL_NOTEQUAL, 0)
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
GL.glEnable(GL.GL_DEPTH_TEST)
def setToolCursor(self, cursorNode): def setToolCursor(self, cursorNode):
if self.cursorNode: if self.cursorNode:
@ -297,6 +283,16 @@ class WorldView(QGLWidget):
for node in overlayNodes: for node in overlayNodes:
self.overlayNode.addChild(node) self.overlayNode.addChild(node)
# --- View settings ---
def setLayerVisible(self, layerName, visible):
self.worldScene.setLayerVisible(layerName, visible)
self.resetLoadOrder()
def setDayTime(self, value):
if self.skyNode:
self.skyNode.setDayTime(value)
def _updateMatrices(self): def _updateMatrices(self):
self.updateMatrices() self.updateMatrices()
self.updateFrustum() self.updateFrustum()
@ -331,7 +327,9 @@ class WorldView(QGLWidget):
:return: :return:
:rtype: list[QVector4D] :rtype: list[QVector4D]
""" """
corners = [QtGui.QVector4D(x, y, z, 1.) for x, y, z in itertools.product((-1., 1.), (-1., 1.), (0., 1. ))] corners = [QtGui.QVector4D(x, y, z, 1.)
for x, y, z in itertools.product((-1., 1.), (-1., 1.), (0., 1.))]
matrix = self.matrixState.projection * self.matrixState.modelview matrix = self.matrixState.projection * self.matrixState.modelview
matrix, inverted = matrix.inverted() matrix, inverted = matrix.inverted()
worldCorners = [matrix.map(corner) for corner in corners] worldCorners = [matrix.map(corner) for corner in corners]
@ -359,17 +357,22 @@ class WorldView(QGLWidget):
return sum(pointPairs, ()) return sum(pointPairs, ())
def resizeGL(self, width, height): scaleChanged = QtCore.Signal(float)
GL.glViewport(0, 0, width, height)
_scale = 1. / 16
@property
def scale(self):
return self._scale
@scale.setter
def scale(self, value):
self._scale = value
self._updateMatrices() self._updateMatrices()
log.debug("update(): scale %s %s", self, value)
def resizeEvent(self, event): self.update()
center = self.viewCenter() self.scaleChanged.emit(value)
self.compassOrtho.size = (1, float(self.height()) / self.width()) self.viewportMoved.emit(self)
super(WorldView, self).resizeEvent(event)
# log.info("WorldView: resized. moving to %s", center)
# self.centerOnPoint(center)
_centerPoint = Vector(0, 0, 0) _centerPoint = Vector(0, 0, 0)
@ -388,23 +391,6 @@ class WorldView(QGLWidget):
self.resetLoadOrder() self.resetLoadOrder()
self.viewportMoved.emit(self) self.viewportMoved.emit(self)
scaleChanged = QtCore.Signal(float)
_scale = 1. / 16
@property
def scale(self):
return self._scale
@scale.setter
def scale(self, value):
self._scale = value
self._updateMatrices()
log.debug("update(): scale %s %s", self, value)
self.update()
self.scaleChanged.emit(value)
self.viewportMoved.emit(self)
def centerOnPoint(self, pos, distance=None): def centerOnPoint(self, pos, distance=None):
"""Center the view on the given position""" """Center the view on the given position"""
# delta = self.viewCenter() - self.centerPoint # delta = self.viewCenter() - self.centerPoint
@ -423,19 +409,40 @@ class WorldView(QGLWidget):
# return point or ray.point # return point or ray.point
return self.centerPoint return self.centerPoint
def _anglesToVector(self, yaw, pitch): # --- Events ---
def nanzero(x):
if math.isnan(x):
return 0
else:
return x
dx = -math.sin(math.radians(yaw)) * math.cos(math.radians(pitch)) def resizeEvent(self, event):
dy = -math.sin(math.radians(pitch)) center = self.viewCenter()
dz = math.cos(math.radians(yaw)) * math.cos(math.radians(pitch)) self.compassOrtho.size = (1, float(self.height()) / self.width())
return Vector(*map(nanzero, [dx, dy, dz])) super(WorldView, self).resizeEvent(event)
# log.info("WorldView: resized. moving to %s", center)
# self.centerOnPoint(center)
dragStart = None acceptableMimeTypes = [
MimeFormats.MapItem,
]
def dragEnterEvent(self, event):
# xxx show drop preview as scene node
print("DRAG ENTER. FORMATS:\n%s" % event.mimeData().formats())
for mimeType in self.acceptableMimeTypes:
if event.mimeData().hasFormat(mimeType):
event.acceptProposedAction()
return
if event.mimeData().hasUrls():
event.acceptProposedAction()
def dropEvent(self, event):
mimeData = event.mimeData()
x = event.pos().x()
y = event.pos().y()
ray = self.rayAtPosition(x, y)
dropPosition, face = self.rayCastInView(ray)
if mimeData.hasFormat(MimeFormats.MapItem):
self.mapItemDropped.emit(mimeData, dropPosition, face)
elif mimeData.hasUrls:
self.urlsDropped.emit(mimeData, dropPosition, face)
def keyPressEvent(self, event): def keyPressEvent(self, event):
self.augmentKeyEvent(event) self.augmentKeyEvent(event)
@ -504,7 +511,6 @@ class WorldView(QGLWidget):
for i in range(abs(clicks)): for i in range(abs(clicks)):
action.keyPressEvent(event) action.keyPressEvent(event)
def augmentMouseEvent(self, event): def augmentMouseEvent(self, event):
x, y = event.x(), event.y() x, y = event.x(), event.y()
return self.augmentEvent(x, y, event) return self.augmentEvent(x, y, event)
@ -534,24 +540,18 @@ class WorldView(QGLWidget):
self.mouseBlockFace = event.blockFace = face self.mouseBlockFace = event.blockFace = face
self.mouseRay = ray self.mouseRay = ray
def rayCastInView(self, ray): # --- OpenGL support ---
try:
result = raycast.rayCastInBounds(ray, self.dimension, maxDistance=200)
position, face = result
except (raycast.MaxDistanceError, ValueError): def initializeGL(self, *args, **kwargs):
# GL.glReadBuffer(GL.GL_BACK) GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
# pixel = GL.glReadPixels(x, self.height() - y, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT) GL.glAlphaFunc(GL.GL_NOTEQUAL, 0)
# depth = -1 + 2 * pixel[0, 0] GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
# p = self.pointsAtPositions((x, y, depth))[0] GL.glEnable(GL.GL_DEPTH_TEST)
#
# face = faces.FaceYIncreasing
# position = p.intfloor()
defaultDistance = 200
position = (ray.point + ray.vector * defaultDistance).intfloor()
face = faces.FaceUp
return position, face def resizeGL(self, width, height):
GL.glViewport(0, 0, width, height)
self._updateMatrices()
maxFPS = 45 maxFPS = 45
@ -588,6 +588,27 @@ class WorldView(QGLWidget):
return (samples - 1) / (self.frameSamples[-1] - self.frameSamples[-samples]) return (samples - 1) / (self.frameSamples[-1] - self.frameSamples[-samples])
# --- Screen<->world space conversion ---
def rayCastInView(self, ray):
try:
result = raycast.rayCastInBounds(ray, self.dimension, maxDistance=200)
position, face = result
except (raycast.MaxDistanceError, ValueError):
# GL.glReadBuffer(GL.GL_BACK)
# pixel = GL.glReadPixels(x, self.height() - y, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT)
# depth = -1 + 2 * pixel[0, 0]
# p = self.pointsAtPositions((x, y, depth))[0]
#
# face = faces.FaceYIncreasing
# position = p.intfloor()
defaultDistance = 200
position = (ray.point + ray.vector * defaultDistance).intfloor()
face = faces.FaceUp
return position, face
def rayAtPosition(self, x, y): def rayAtPosition(self, x, y):
""" """
Given coordinates in screen space, return a ray in 3D space. Given coordinates in screen space, return a ray in 3D space.
@ -637,6 +658,8 @@ class WorldView(QGLWidget):
ray = self.rayAtPosition(x, y) ray = self.rayAtPosition(x, y)
return ray.atHeight(h) return ray.atHeight(h)
# --- Chunk loading ---
_chunkIter = None _chunkIter = None
def resetLoadOrder(self): def resetLoadOrder(self):
@ -701,14 +724,6 @@ class WorldView(QGLWidget):
self.resetLoadOrder() self.resetLoadOrder()
def setLayerVisible(self, layerName, visible):
self.worldScene.setLayerVisible(layerName, visible)
self.resetLoadOrder()
def setDayTime(self, value):
if self.skyNode:
self.skyNode.setDayTime(value)
def iterateChunks(x, z, radius): def iterateChunks(x, z, radius):
""" """
Yields a list of chunk positions starting from the center and going outward in a square spiral pattern. Yields a list of chunk positions starting from the center and going outward in a square spiral pattern.