mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-05 03:15:07 -04:00
582 lines
22 KiB
Python
582 lines
22 KiB
Python
from PandaObject import *
|
|
from DirectGeometry import *
|
|
|
|
CAM_MOVE_DURATION = 1.2
|
|
COA_MARKER_SF = 0.0075
|
|
Y_AXIS = Vec3(0,1,0)
|
|
|
|
class DirectCameraControl(PandaObject):
|
|
def __init__(self):
|
|
# Create the grid
|
|
self.orthoViewRoll = 0.0
|
|
self.lastView = 0
|
|
self.coa = Point3(0,100,0)
|
|
self.coaDist = 100
|
|
self.coaMarker = loader.loadModel('models/misc/sphere')
|
|
self.coaMarker.setName('DirectCameraCOAMarker')
|
|
self.coaMarker.setTransparency(1)
|
|
self.coaMarker.setColor(1,0,0)
|
|
self.coaMarker.setPos(0,100,0)
|
|
useDirectRenderStyle(self.coaMarker)
|
|
self.coaMarkerPos = Point3(0)
|
|
self.fUpdateCOA = 1
|
|
self.camManipRef = direct.group.attachNewNode('camManipRef')
|
|
t = CAM_MOVE_DURATION
|
|
self.actionEvents = [
|
|
['DIRECT_mouse2', self.mouseFlyStart],
|
|
['DIRECT_mouse2Up', self.mouseFlyStop],
|
|
['c', self.centerCamIn, 0.5],
|
|
['f', self.fitOnWidget],
|
|
['h', self.homeCam],
|
|
['i', self.toggleMarkerVis],
|
|
['m', self.moveToFit],
|
|
['n', self.pickNextCOA],
|
|
['u', self.orbitUprightCam],
|
|
['U', self.uprightCam],
|
|
[`1`, self.spawnMoveToView, 1],
|
|
[`2`, self.spawnMoveToView, 2],
|
|
[`3`, self.spawnMoveToView, 3],
|
|
[`4`, self.spawnMoveToView, 4],
|
|
[`5`, self.spawnMoveToView, 5],
|
|
[`6`, self.spawnMoveToView, 6],
|
|
[`7`, self.spawnMoveToView, 7],
|
|
[`8`, self.spawnMoveToView, 8],
|
|
['9', self.swingCamAboutWidget, -90.0, t],
|
|
['0', self.swingCamAboutWidget, 90.0, t],
|
|
['`', self.removeManipulateCameraTask],
|
|
['=', self.zoomCam, 0.5, t],
|
|
['+', self.zoomCam, 0.5, t],
|
|
['-', self.zoomCam, -2.0, t],
|
|
['_', self.zoomCam, -2.0, t],
|
|
]
|
|
|
|
def toggleMarkerVis(self):
|
|
if direct.cameraControl.coaMarker.isHidden():
|
|
direct.cameraControl.coaMarker.show()
|
|
else:
|
|
direct.cameraControl.coaMarker.hide()
|
|
|
|
def mouseFlyStart(self):
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
# Where are we in the display region?
|
|
if ((abs(direct.dr.mouseX) < 0.9) and (abs(direct.dr.mouseY) < 0.9)):
|
|
# MOUSE IS IN CENTRAL REGION
|
|
# Hide the marker for this kind of motion
|
|
self.coaMarker.hide()
|
|
# Check for a hit point based on
|
|
# current mouse position
|
|
# Allow intersection with unpickable objects
|
|
# And then spawn task to determine mouse mode
|
|
node, hitPt, hitPtDist = direct.iRay.pickGeom(
|
|
fIntersectUnpickable = 1)
|
|
self.computeCOA(node, hitPt, hitPtDist)
|
|
# Start manipulation
|
|
self.spawnXZTranslateOrHPanYZoom()
|
|
# END MOUSE IN CENTRAL REGION
|
|
else:
|
|
if ((abs(direct.dr.mouseX) > 0.9) and
|
|
(abs(direct.dr.mouseY) > 0.9)):
|
|
# Mouse is in corners, spawn roll task
|
|
self.spawnMouseRollTask()
|
|
else:
|
|
# Mouse is in outer frame, spawn mouseRotateTask
|
|
self.spawnMouseRotateTask()
|
|
|
|
def mouseFlyStop(self):
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Show the marker
|
|
self.coaMarker.show()
|
|
# Resize it
|
|
self.updateCoaMarkerSize()
|
|
|
|
def spawnXZTranslateOrHPanYZoom(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Spawn the new task
|
|
t = Task.Task(self.XZTranslateOrHPanYZoomTask)
|
|
# For HPanYZoom
|
|
t.zoomSF = Vec3(self.coa).length()
|
|
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
|
|
|
def spawnXZTranslateOrHPPan(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Spawn new task
|
|
taskMgr.spawnMethodNamed(self.XZTranslateOrHPPanTask,
|
|
'manipulateCamera')
|
|
|
|
def spawnXZTranslate(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Spawn new task
|
|
taskMgr.spawnMethodNamed(self.XZTranslateTask, 'manipulateCamera')
|
|
|
|
def spawnHPanYZoom(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Spawn new task
|
|
t = Task.Task(self.HPanYZoomTask)
|
|
t.zoomSF = Vec3(self.coa).length()
|
|
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
|
|
|
def spawnHPPan(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Spawn new task
|
|
taskMgr.spawnMethodNamed(self.HPPanTask, 'manipulateCamera')
|
|
|
|
def XZTranslateOrHPanYZoomTask(self, state):
|
|
if direct.fShift:
|
|
return self.XZTranslateTask(state)
|
|
else:
|
|
return self.HPanYZoomTask(state)
|
|
|
|
def XZTranslateOrHPPanTask(self, state):
|
|
if direct.fShift:
|
|
# Panning action
|
|
return self.HPPanTask(state)
|
|
else:
|
|
# Translation action
|
|
return self.XZTranslateTask(state)
|
|
|
|
def XZTranslateTask(self,state):
|
|
coaDist = Vec3(self.coaMarker.getPos(direct.camera)).length()
|
|
xlateSF = (coaDist / direct.dr.near)
|
|
direct.camera.setPos(direct.camera,
|
|
(-0.5 * direct.dr.mouseDeltaX *
|
|
direct.dr.nearWidth *
|
|
xlateSF),
|
|
0.0,
|
|
(-0.5 * direct.dr.mouseDeltaY *
|
|
direct.dr.nearHeight *
|
|
xlateSF))
|
|
return Task.cont
|
|
|
|
def HPanYZoomTask(self,state):
|
|
if direct.fControl:
|
|
moveDir = Vec3(Y_AXIS)
|
|
else:
|
|
moveDir = Vec3(self.coaMarker.getPos(direct.camera))
|
|
# If marker is behind camera invert vector
|
|
if moveDir[1] < 0.0:
|
|
moveDir.assign(moveDir * -1)
|
|
moveDir.normalize()
|
|
moveDir.assign(moveDir * (-2.0 * direct.dr.mouseDeltaY *
|
|
state.zoomSF))
|
|
direct.camera.setPosHpr(direct.camera,
|
|
moveDir[0],
|
|
moveDir[1],
|
|
moveDir[2],
|
|
(0.5 * direct.dr.mouseDeltaX *
|
|
direct.dr.fovH),
|
|
0.0, 0.0)
|
|
return Task.cont
|
|
|
|
def HPPanTask(self, state):
|
|
direct.camera.setHpr(direct.camera,
|
|
(0.5 * direct.dr.mouseDeltaX *
|
|
direct.dr.fovH),
|
|
(-0.5 * direct.dr.mouseDeltaY *
|
|
direct.dr.fovV),
|
|
0.0)
|
|
return Task.cont
|
|
|
|
def spawnMouseRotateTask(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Set at markers position in render coordinates
|
|
self.camManipRef.setPos(self.coaMarkerPos)
|
|
self.camManipRef.setHpr(direct.camera, ZERO_POINT)
|
|
t = Task.Task(self.mouseRotateTask)
|
|
if abs(direct.dr.mouseX) > 0.9:
|
|
t.constrainedDir = 'y'
|
|
else:
|
|
t.constrainedDir = 'x'
|
|
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
|
|
|
def mouseRotateTask(self, state):
|
|
# If moving outside of center, ignore motion perpendicular to edge
|
|
if ((state.constrainedDir == 'y') and (abs(direct.dr.mouseX) > 0.9)):
|
|
deltaX = 0
|
|
deltaY = direct.dr.mouseDeltaY
|
|
elif ((state.constrainedDir == 'x') and (abs(direct.dr.mouseY) > 0.9)):
|
|
deltaX = direct.dr.mouseDeltaX
|
|
deltaY = 0
|
|
else:
|
|
deltaX = direct.dr.mouseDeltaX
|
|
deltaY = direct.dr.mouseDeltaY
|
|
if direct.fShift:
|
|
direct.camera.setHpr(direct.camera,
|
|
(deltaX * direct.dr.fovH),
|
|
(-deltaY * direct.dr.fovV),
|
|
0.0)
|
|
self.camManipRef.setPos(self.coaMarkerPos)
|
|
self.camManipRef.setHpr(direct.camera, ZERO_POINT)
|
|
else:
|
|
wrtMat = direct.camera.getMat( self.camManipRef )
|
|
self.camManipRef.setHpr(self.camManipRef,
|
|
(-1 * deltaX * 180.0),
|
|
(deltaY * 180.0),
|
|
0.0)
|
|
direct.camera.setMat(self.camManipRef, wrtMat)
|
|
return Task.cont
|
|
|
|
def spawnMouseRollTask(self):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Set at markers position in render coordinates
|
|
self.camManipRef.setPos(self.coaMarkerPos)
|
|
self.camManipRef.setHpr(direct.camera, ZERO_POINT)
|
|
t = Task.Task(self.mouseRollTask)
|
|
t.coaCenter = getScreenXY(self.coaMarker)
|
|
t.lastAngle = getCrankAngle(t.coaCenter)
|
|
t.wrtMat = direct.camera.getMat( self.camManipRef )
|
|
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
|
|
|
def mouseRollTask(self, state):
|
|
wrtMat = state.wrtMat
|
|
angle = getCrankAngle(state.coaCenter)
|
|
deltaAngle = angle - state.lastAngle
|
|
state.lastAngle = angle
|
|
if base.config.GetBool('temp-hpr-fix',0):
|
|
self.camManipRef.setHpr(self.camManipRef, 0, 0, deltaAngle)
|
|
else:
|
|
self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle)
|
|
direct.camera.setMat(self.camManipRef, wrtMat)
|
|
return Task.cont
|
|
|
|
def lockCOA(self):
|
|
self.fUpdateCOA = 0
|
|
|
|
def unlockCOA(self):
|
|
self.fUpdateCOA = 1
|
|
|
|
def toggleCOALock(self):
|
|
self.fUpdateCOA = 1 - self.fUpdateCOA
|
|
|
|
def pickNextCOA(self):
|
|
""" Cycle through collision handler entries """
|
|
node, hitPt, hitPtDist = direct.iRay.pickNext()
|
|
self.computeCOA(node, hitPt, hitPtDist)
|
|
|
|
def computeCOA(self, node, hitPt, hitPtDist):
|
|
coa = Point3(0)
|
|
if self.fUpdateCOA and node:
|
|
# Set center of action
|
|
coa.assign(hitPt)
|
|
coaDist = hitPtDist
|
|
# Handle case of bad coa point (too close or too far)
|
|
if ((coaDist < (1.1 * direct.dr.near)) or
|
|
(coaDist > direct.dr.far)):
|
|
# Just use existing point
|
|
coa.assign(self.coaMarker.getPos(direct.camera))
|
|
coaDist = Vec3(coa - ZERO_POINT).length()
|
|
if coaDist < (1.1 * direct.dr.near):
|
|
coa.set(0,100,0)
|
|
coaDist = 100
|
|
else:
|
|
# If no intersection point or COA is locked:
|
|
# Use existing point
|
|
coa.assign(self.coaMarker.getPos(direct.camera))
|
|
coaDist = Vec3(coa - ZERO_POINT).length()
|
|
# Check again its not to close
|
|
if coaDist < (1.1 * direct.dr.near):
|
|
coa.set(0,100,0)
|
|
coaDist = 100
|
|
# Update coa and marker
|
|
self.updateCoa(coa, coaDist)
|
|
|
|
def updateCoa(self, cam2point, coaDist = None):
|
|
self.coa.set(cam2point[0], cam2point[1], cam2point[2])
|
|
if coaDist:
|
|
self.coaDist = coaDist
|
|
else:
|
|
self.coaDist = Vec3(self.coa - ZERO_POINT).length()
|
|
# Place the marker in render space
|
|
self.coaMarker.setPos(direct.camera,self.coa)
|
|
# Resize it
|
|
self.updateCoaMarkerSize(coaDist)
|
|
# Record marker pos in render space
|
|
self.coaMarkerPos.assign(self.coaMarker.getPos())
|
|
|
|
def updateCoaMarkerSizeOnDeath(self, state):
|
|
# Needed because tasks pass in state as first arg
|
|
self.updateCoaMarkerSize()
|
|
|
|
def updateCoaMarkerSize(self, coaDist = None):
|
|
if not coaDist:
|
|
coaDist = Vec3(self.coaMarker.getPos( direct.camera )).length()
|
|
sf = COA_MARKER_SF * coaDist * math.tan(deg2Rad(direct.dr.fovV))
|
|
if sf == 0.0:
|
|
sf = 0.1
|
|
self.coaMarker.setScale(sf)
|
|
# Lerp color to fade out
|
|
self.coaMarker.lerpColor(VBase4(1,0,0,1), VBase4(1,0,0,0), 3.0,
|
|
task = 'fadeAway')
|
|
|
|
def homeCam(self):
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
direct.camera.reparentTo(render)
|
|
direct.camera.setMat(Mat4.identMat())
|
|
# Resize coa marker
|
|
self.updateCoaMarkerSize()
|
|
|
|
def uprightCam(self):
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
# Pitch camera till upright
|
|
currH = direct.camera.getH()
|
|
direct.camera.lerpHpr(currH, 0, 0,
|
|
CAM_MOVE_DURATION,
|
|
other = render,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
|
|
def orbitUprightCam(self):
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
# Transform camera z axis to render space
|
|
mCam2Render = camera.getMat(render)
|
|
zAxis = Vec3(mCam2Render.xformVec(Z_AXIS))
|
|
zAxis.normalize()
|
|
# Compute rotation angle needed to upright cam
|
|
orbitAngle = rad2Deg(math.acos(CLAMP(zAxis.dot(Z_AXIS),-1,1)))
|
|
# Check angle
|
|
if orbitAngle < 0.1:
|
|
# Already upright
|
|
return
|
|
# Compute orthogonal axis of rotation
|
|
rotAxis = Vec3(zAxis.cross(Z_AXIS))
|
|
rotAxis.normalize()
|
|
# Find angle between rot Axis and render X_AXIS
|
|
rotAngle = rad2Deg(math.acos(CLAMP(rotAxis.dot(X_AXIS),-1,1)))
|
|
# Determine sign or rotation angle
|
|
if rotAxis[1] < 0:
|
|
rotAngle *= -1
|
|
# Position ref CS at coa marker with xaxis aligned with rot axis
|
|
self.camManipRef.setPos(self.coaMarker, Vec3(0))
|
|
self.camManipRef.setHpr(render, rotAngle, 0, 0)
|
|
# Reparent Cam to ref Coordinate system
|
|
parent = direct.camera.getParent()
|
|
direct.camera.wrtReparentTo(self.camManipRef)
|
|
# Rotate ref CS to final orientation
|
|
t = self.camManipRef.lerpHpr(rotAngle, orbitAngle, 0,
|
|
CAM_MOVE_DURATION,
|
|
other = render,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
# Upon death, reparent Cam to parent
|
|
t.parent = parent
|
|
t.uponDeath = self.reparentCam
|
|
|
|
def centerCam(self):
|
|
self.centerCamIn(1.0)
|
|
|
|
def centerCamNow(self):
|
|
self.centerCamIn(0.)
|
|
|
|
def centerCamIn(self, t):
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
# Determine marker location
|
|
markerToCam = self.coaMarker.getPos( direct.camera )
|
|
dist = Vec3(markerToCam - ZERO_POINT).length()
|
|
scaledCenterVec = Y_AXIS * dist
|
|
delta = markerToCam - scaledCenterVec
|
|
self.camManipRef.setPosHpr(direct.camera, Point3(0), Point3(0))
|
|
t = direct.camera.lerpPos(Point3(delta),
|
|
CAM_MOVE_DURATION,
|
|
other = self.camManipRef,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
t.uponDeath = self.updateCoaMarkerSizeOnDeath
|
|
|
|
def zoomCam(self, zoomFactor, t):
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
# Find a point zoom factor times the current separation
|
|
# of the widget and cam
|
|
zoomPtToCam = self.coaMarker.getPos(direct.camera) * zoomFactor
|
|
# Put a target nodePath there
|
|
self.camManipRef.setPos(direct.camera, zoomPtToCam)
|
|
# Move to that point
|
|
t = direct.camera.lerpPos(ZERO_POINT,
|
|
CAM_MOVE_DURATION,
|
|
other = self.camManipRef,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
t.uponDeath = self.updateCoaMarkerSizeOnDeath
|
|
|
|
def spawnMoveToView(self, view):
|
|
# Kill any existing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
# Calc hprOffset
|
|
hprOffset = VBase3()
|
|
if view == 8:
|
|
# Try the next roll angle
|
|
self.orthoViewRoll = (self.orthoViewRoll + 90.0) % 360.0
|
|
# but use the last view
|
|
view = self.lastView
|
|
else:
|
|
self.orthoViewRoll = 0.0
|
|
# Adjust offset based on specified view
|
|
if view == 1:
|
|
hprOffset.set(180., 0., 0.)
|
|
elif view == 2:
|
|
hprOffset.set(0., 0., 0.)
|
|
elif view == 3:
|
|
hprOffset.set(90., 0., 0.)
|
|
elif view == 4:
|
|
hprOffset.set(-90., 0., 0.)
|
|
elif view == 5:
|
|
hprOffset.set(0., -90., 0.)
|
|
elif view == 6:
|
|
hprOffset.set(0., 90., 0.)
|
|
elif view == 7:
|
|
hprOffset.set(135., -35.264, 0.)
|
|
# Position target
|
|
self.camManipRef.setPosHpr(self.coaMarker, ZERO_VEC,
|
|
hprOffset)
|
|
# Scale center vec by current distance to target
|
|
offsetDistance = Vec3(direct.camera.getPos(self.camManipRef) -
|
|
ZERO_POINT).length()
|
|
scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
|
|
# Now put the camManipRef at that point
|
|
self.camManipRef.setPosHpr(self.camManipRef,
|
|
scaledCenterVec,
|
|
ZERO_VEC)
|
|
# Record view for next time around
|
|
self.lastView = view
|
|
t = direct.camera.lerpPosHpr(ZERO_POINT,
|
|
VBase3(0,0,self.orthoViewRoll),
|
|
CAM_MOVE_DURATION,
|
|
other = self.camManipRef,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
t.uponDeath = self.updateCoaMarkerSizeOnDeath
|
|
|
|
|
|
def swingCamAboutWidget(self, degrees, t):
|
|
# Remove existing camera manipulation task
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
|
|
# Record undo point
|
|
direct.pushUndo([direct.camera])
|
|
|
|
# Coincident with widget
|
|
self.camManipRef.setPos(self.coaMarker, ZERO_POINT)
|
|
# But aligned with render space
|
|
self.camManipRef.setHpr(ZERO_POINT)
|
|
|
|
parent = direct.camera.getParent()
|
|
direct.camera.wrtReparentTo(self.camManipRef)
|
|
|
|
manipTask = self.camManipRef.lerpHpr(VBase3(degrees,0,0),
|
|
CAM_MOVE_DURATION,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
# Upon death, reparent Cam to parent
|
|
manipTask.parent = parent
|
|
manipTask.uponDeath = self.reparentCam
|
|
|
|
def reparentCam(self, state):
|
|
direct.camera.wrtReparentTo(state.parent)
|
|
self.updateCoaMarkerSize()
|
|
|
|
def fitOnWidget(self, nodePath = 'None Given'):
|
|
# Fit the node on the screen
|
|
# stop any ongoing tasks
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
# How big is the node?
|
|
nodeScale = direct.widget.scalingNode.getScale(render)
|
|
maxScale = max(nodeScale[0],nodeScale[1],nodeScale[2])
|
|
maxDim = min(direct.dr.nearWidth, direct.dr.nearHeight)
|
|
|
|
# At what distance does the object fill 30% of the screen?
|
|
# Assuming radius of 1 on widget
|
|
camY = direct.dr.near * (2.0 * maxScale)/(0.3 * maxDim)
|
|
|
|
# What is the vector through the center of the screen?
|
|
centerVec = Y_AXIS * camY
|
|
|
|
# Where is the node relative to the viewpoint
|
|
vWidget2Camera = direct.widget.getPos(direct.camera)
|
|
|
|
# How far do you move the camera to be this distance from the node?
|
|
deltaMove = vWidget2Camera - centerVec
|
|
|
|
# Move a target there
|
|
self.camManipRef.setPos(direct.camera, deltaMove)
|
|
|
|
parent = direct.camera.getParent()
|
|
direct.camera.wrtReparentTo(self.camManipRef)
|
|
fitTask = direct.camera.lerpPos(Point3(0,0,0),
|
|
CAM_MOVE_DURATION,
|
|
blendType = 'easeInOut',
|
|
task = 'manipulateCamera')
|
|
# Upon death, reparent Cam to parent
|
|
fitTask.parent = parent
|
|
fitTask.uponDeath = self.reparentCam
|
|
|
|
def moveToFit(self):
|
|
# How bit is the active widget?
|
|
widgetScale = direct.widget.scalingNode.getScale(render)
|
|
maxScale = max(widgetScale[0], widgetScale[1], widgetScale[2])
|
|
# At what distance does the widget fill 50% of the screen?
|
|
camY = ((2 * direct.dr.near * (1.5 * maxScale)) /
|
|
min(direct.dr.nearWidth, direct.dr.nearHeight))
|
|
# Find a point this distance along the Y axis
|
|
# MRM: This needs to be generalized to support non uniform frusta
|
|
centerVec = Y_AXIS * camY
|
|
# Before moving, record the relationship between the selected nodes
|
|
# and the widget, so that this can be maintained
|
|
direct.selected.getWrtAll()
|
|
# Push state onto undo stack
|
|
direct.pushUndo(direct.selected)
|
|
# Remove the task to keep the widget attached to the object
|
|
taskMgr.removeTasksNamed('followSelectedNodePath')
|
|
# Spawn a task to keep the selected objects with the widget
|
|
taskMgr.spawnMethodNamed(self.stickToWidgetTask, 'stickToWidget')
|
|
# Spawn a task to move the widget
|
|
t = direct.widget.lerpPos(Point3(centerVec),
|
|
CAM_MOVE_DURATION,
|
|
other = direct.camera,
|
|
blendType = 'easeInOut',
|
|
task = 'moveToFitTask')
|
|
t.uponDeath = lambda state: taskMgr.removeTasksNamed('stickToWidget')
|
|
|
|
def stickToWidgetTask(self, state):
|
|
# Move the objects with the widget
|
|
direct.selected.moveWrtWidgetAll()
|
|
# Continue
|
|
return Task.cont
|
|
|
|
def enableMouseFly(self):
|
|
# disable C++ fly interface
|
|
base.disableMouse()
|
|
# Enable events
|
|
for event in self.actionEvents:
|
|
self.accept(event[0], event[1], extraArgs = event[2:])
|
|
# Show marker
|
|
self.coaMarker.reparentTo(direct.group)
|
|
|
|
def disableMouseFly(self):
|
|
# Hide the marker
|
|
self.coaMarker.reparentTo(hidden)
|
|
# Ignore events
|
|
for event in self.actionEvents:
|
|
self.ignore(event[0])
|
|
base.enableMouse()
|
|
|
|
def removeManipulateCameraTask(self):
|
|
taskMgr.removeTasksNamed('manipulateCamera')
|
|
|