*** empty log message ***

This commit is contained in:
Mark Mine 2001-01-15 04:21:16 +00:00
parent 1a1b9ae9c2
commit 8ecb2f612c
5 changed files with 455 additions and 287 deletions

View File

@ -1,5 +1,5 @@
from PandaObject import *
from DirectGeometry import useDirectRenderStyle
from DirectGeometry import *
CAM_MOVE_DURATION = 1.0
COA_MARKER_SF = 0.0075
@ -19,26 +19,24 @@ class DirectCameraControl(PandaObject):
useDirectRenderStyle(self.coaMarker)
self.coaMarkerPos = Point3(0)
self.camManipRef = direct.group.attachNewNode('camManipRef')
self.zeroBaseVec = VBase3(0)
self.zeroVector = Vec3(0)
self.centerVec = Vec3(0, 1, 0)
self.zeroPoint = Point3(0)
t = CAM_MOVE_DURATION
self.actionEvents = [
['handleMouse2', self.mouseFlyStart],
['handleMouse2Up', self.mouseFlyStop],
['u', self.uprightCam],
['c', self.centerCamIn, 0.5],
['h', self.homeCam],
['f', self.fitOnWidget],
[`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],
['h', self.homeCam],
['m', self.moveToFit],
['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],
@ -59,102 +57,241 @@ class DirectCameraControl(PandaObject):
# MOUSE IS IN CENTRAL REGION
# Hide the marker for this kind of motion
self.coaMarker.hide()
# See if the shift key is pressed
if (direct.fShift):
# If shift key is pressed, just perform horiz and vert pan:
self.spawnHPPan()
else:
# Otherwise, check for a hit point based on
# current mouse position
# And then spawn task to determine mouse mode
numEntries = direct.iRay.pickGeom(
render,direct.dr.mouseX,direct.dr.mouseY)
# Filter out hidden nodes from entry list
indexList = []
for i in range(0,numEntries):
entry = direct.iRay.cq.getEntry(i)
node = entry.getIntoNode()
if node.isHidden():
pass
else:
# Not one of the widgets, use it
indexList.append(i)
coa = Point3(0)
if(indexList):
# Start off with first point
minPt = indexList[0]
# Find hit point in camera's space
hitPt = direct.iRay.camToHitPt(minPt)
coa.set(hitPt[0],hitPt[1],hitPt[2])
coaDist = Vec3(coa - self.zeroPoint).length()
# Check other intersection points, sorting them
# TBD: Use TBS C++ function to do this
if len(indexList) > 1:
for i in range(1,len(indexList)):
entryNum = indexList[i]
hitPt = direct.iRay.camToHitPt(entryNum)
dist = Vec3(hitPt - self.zeroPoint).length()
if (dist < coaDist):
coaDist = dist
coa.set(hitPt[0],hitPt[1],hitPt[2])
minPt = i
# Handle case of bad coa point (too close or too far)
if ((coaDist < (1.1 * direct.dr.near)) |
(coaDist > direct.dr.far)):
# Just use existing point
coa.assign(self.coaMarker.getPos(direct.camera))
coaDist = Vec3(coa - self.zeroPoint).length()
if coaDist < (1.1 * direct.dr.near):
coa.set(0,100,0)
coaDist = 100
# Check for a hit point based on
# current mouse position
# And then spawn task to determine mouse mode
numEntries = direct.iRay.pickGeom(
render,direct.dr.mouseX,direct.dr.mouseY)
# Sort intersection points
direct.iRay.cq.sortEntries()
# Then filter out hidden nodes from entry list
indexList = []
for i in range(0,numEntries):
entry = direct.iRay.cq.getEntry(i)
node = entry.getIntoNode()
if node.isHidden():
pass
else:
# If no intersection point:
# Use existing point
# Not one of the widgets, use it
indexList.append(i)
coa = Point3(0)
if(indexList):
# Grab first point (it should be the closest)
minPt = indexList[0]
# Find hit point in camera's space
hitPt = direct.iRay.camToHitPt(minPt)
coa.set(hitPt[0],hitPt[1],hitPt[2])
coaDist = Vec3(coa - ZERO_POINT).length()
"""
# Check other intersection points, sorting them
# TBD: Use TBS C++ function to do this
if len(indexList) > 1:
for i in range(1,len(indexList)):
entryNum = indexList[i]
hitPt = direct.iRay.camToHitPt(entryNum)
dist = Vec3(hitPt - ZERO_POINT).length()
if (dist < coaDist):
coaDist = dist
coa.set(hitPt[0],hitPt[1],hitPt[2])
minPt = i
"""
# Handle case of bad coa point (too close or too far)
if ((coaDist < (1.1 * direct.dr.near)) |
(coaDist > direct.dr.far)):
# Just use existing point
coa.assign(self.coaMarker.getPos(direct.camera))
coaDist = Vec3(coa - self.zeroPoint).length()
coaDist = Vec3(coa - ZERO_POINT).length()
if coaDist < (1.1 * direct.dr.near):
coa.set(0,100,0)
coaDist = 100
# Update coa and marker
self.updateCoa(coa, coaDist)
# Now spawn task to determine mouse fly mode
self.determineMouseFlyMode()
else:
# If no intersection point:
# 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)
# Start manipulation
self.spawnXZTranslateOrHPanYZoom()
# END MOUSE IN CENTRAL REGION
else:
# Mouse is in outer frame, spawn mouseRotateTask
self.spawnMouseRotateTask()
if ((abs(self.initMouseX) > 0.9) & (abs(self.initMouseY) > 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('determineMouseFlyMode')
taskMgr.removeTasksNamed('manipulateCamera')
# Show the marker
self.coaMarker.show()
# Resize it
self.updateCoaMarkerSize()
def determineMouseFlyMode(self):
# Otherwise, determine mouse fly mode
t = Task.Task(self.determineMouseFlyModeTask)
taskMgr.spawnTaskNamed(t, 'determineMouseFlyMode')
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 determineMouseFlyModeTask(self, state):
deltaX = direct.dr.mouseX - self.initMouseX
deltaY = direct.dr.mouseY - self.initMouseY
if ((abs(deltaX) < 0.1) & (abs(deltaY) < 0.1)):
return Task.cont
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:
if (abs(deltaY) > 0.1):
self.spawnHPanYZoom()
else:
self.spawnXZTranslate()
return Task.done
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 within frame, ignore motion perpendicular to edge
if ((state.constrainedDir == 'y') & (abs(direct.dr.mouseX) > 0.9)):
deltaX = 0
deltaY = direct.dr.mouseDeltaY
elif ((state.constrainedDir == 'x') & (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
self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle)
direct.camera.setMat(self.camManipRef, wrtMat)
return Task.cont
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 - self.zeroPoint).length()
self.coaDist = Vec3(self.coa - ZERO_POINT).length()
# Place the marker in render space
self.coaMarker.setPos(direct.camera,self.coa)
# Resize it
@ -162,6 +299,10 @@ class DirectCameraControl(PandaObject):
# 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()
@ -172,18 +313,59 @@ class DirectCameraControl(PandaObject):
# Record undo point
direct.pushUndo([direct.camera])
direct.camera.setMat(Mat4.identMat())
# Resize coa marker
self.updateCoaMarkerSize()
def uprightCam(self):
taskMgr.removeTasksNamed('manipulateCamera')
currH = direct.camera.getH()
# 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)
@ -196,15 +378,16 @@ class DirectCameraControl(PandaObject):
direct.pushUndo([direct.camera])
# Determine marker location
markerToCam = self.coaMarker.getPos( direct.camera )
dist = Vec3(markerToCam - self.zeroPoint).length()
scaledCenterVec = self.centerVec * dist
dist = Vec3(markerToCam - ZERO_POINT).length()
scaledCenterVec = Y_AXIS * dist
delta = markerToCam - scaledCenterVec
self.camManipRef.setPosHpr(direct.camera, Point3(0), Point3(0))
direct.camera.lerpPos(Point3(delta),
CAM_MOVE_DURATION,
other = self.camManipRef,
blendType = 'easeInOut',
task = 'manipulateCamera')
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')
@ -216,13 +399,14 @@ class DirectCameraControl(PandaObject):
# Put a target nodePath there
self.camManipRef.setPos(direct.camera, zoomPtToCam)
# Move to that point
direct.camera.lerpPos(self.zeroPoint,
CAM_MOVE_DURATION,
other = self.camManipRef,
blendType = 'easeInOut',
task = 'manipulateCamera')
t = direct.camera.lerpPos(ZERO_POINT,
CAM_MOVE_DURATION,
other = self.camManipRef,
blendType = 'easeInOut',
task = 'manipulateCamera')
t.uponDeath = self.updateCoaMarkerSizeOnDeath
def SpawnMoveToView(self, view):
def spawnMoveToView(self, view):
# Kill any existing tasks
taskMgr.removeTasksNamed('manipulateCamera')
# Record undo point
@ -252,25 +436,26 @@ class DirectCameraControl(PandaObject):
elif view == 7:
hprOffset.set(135., -35.264, 0.)
# Position target
self.camManipRef.setPosHpr(self.coaMarker, self.zeroBaseVec,
self.camManipRef.setPosHpr(self.coaMarker, ZERO_VEC,
hprOffset)
# Scale center vec by current distance to target
offsetDistance = Vec3(direct.camera.getPos(self.camManipRef) -
self.zeroPoint).length()
scaledCenterVec = self.centerVec * (-1.0 * offsetDistance)
ZERO_POINT).length()
scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
# Now put the camManipRef at that point
self.camManipRef.setPosHpr(self.camManipRef,
scaledCenterVec,
self.zeroBaseVec)
ZERO_VEC)
# Record view for next time around
self.lastView = view
direct.camera.lerpPosHpr(self.zeroPoint,
VBase3(0,0,self.orthoViewRoll),
CAM_MOVE_DURATION,
other = self.camManipRef,
blendType = 'easeInOut',
task = 'manipulateCamera')
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
@ -280,9 +465,9 @@ class DirectCameraControl(PandaObject):
direct.pushUndo([direct.camera])
# Coincident with widget
self.camManipRef.setPos(self.coaMarker, self.zeroPoint)
self.camManipRef.setPos(self.coaMarker, ZERO_POINT)
# But aligned with render space
self.camManipRef.setHpr(self.zeroPoint)
self.camManipRef.setHpr(ZERO_POINT)
parent = direct.camera.getParent()
direct.camera.wrtReparentTo(self.camManipRef)
@ -297,115 +482,7 @@ class DirectCameraControl(PandaObject):
def reparentCam(self, state):
direct.camera.wrtReparentTo(state.parent)
def spawnHPanYZoom(self):
# Kill any existing tasks
taskMgr.removeTasksNamed('manipulateCamera')
# hide the marker
self.coaMarker.hide()
# Negate vec to give it the correct sense for mouse motion below
targetVector = self.coa * -1
t = Task.Task(self.HPanYZoomTask)
t.targetVector = targetVector
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
def HPanYZoomTask(self,state):
targetVector = state.targetVector
# Can bring object to you by dragging across half the screen
distToMove = targetVector * (2.0 * direct.dr.mouseDeltaY)
direct.camera.setPosHpr(direct.camera,
distToMove[0],
distToMove[1],
distToMove[2],
(0.5 * direct.dr.mouseDeltaX *
direct.dr.fovH),
0.0, 0.0)
return Task.cont
def spawnXZTranslateOrHPPan(self):
# Kill any existing tasks
taskMgr.removeTasksNamed('manipulateCamera')
# Hide the marker
self.coaMarker.hide()
t = Task.Task(self.XZTranslateOrHPPanTask)
t.scaleFactor = (self.coaDist / direct.dr.near)
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
def XZTranslateOrHPPanTask(self, state):
if direct.fShift:
direct.camera.setHpr(direct.camera,
(0.5 * direct.dr.mouseDeltaX *
direct.dr.fovH),
(-0.5 * direct.dr.mouseDeltaY *
direct.dr.fovV),
0.0)
else:
direct.camera.setPos(direct.camera,
(-0.5 * direct.dr.mouseDeltaX *
direct.dr.nearWidth *
state.scaleFactor),
0.0,
(-0.5 * direct.dr.mouseDeltaY *
direct.dr.nearHeight *
state.scaleFactor))
return Task.cont
def spawnXZTranslate(self):
# Kill any existing tasks
taskMgr.removeTasksNamed('manipulateCamera')
# Hide the marker
self.coaMarker.hide()
t = Task.Task(self.XZTranslateTask)
t.scaleFactor = (self.coaDist / direct.dr.near)
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
def XZTranslateTask(self,state):
direct.camera.setPos(direct.camera,
(-0.5 * direct.dr.mouseDeltaX *
direct.dr.nearWidth *
state.scaleFactor),
0.0,
(-0.5 * direct.dr.mouseDeltaY *
direct.dr.nearHeight *
state.scaleFactor))
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, self.zeroPoint)
t = Task.Task(self.mouseRotateTask)
t.wrtMat = direct.camera.getMat( self.camManipRef )
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
def mouseRotateTask(self, state):
wrtMat = state.wrtMat
self.camManipRef.setHpr(self.camManipRef,
(-0.5 * direct.dr.mouseDeltaX * 180.0),
(0.5 * direct.dr.mouseDeltaY * 180.0),
0.0)
direct.camera.setMat(self.camManipRef, wrtMat)
return Task.cont
def spawnHPPan(self):
# Kill any existing tasks
taskMgr.removeTasksNamed('manipulateCamera')
# Hide the marker
self.coaMarker.hide()
t = Task.Task(self.HPPanTask)
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
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
self.updateCoaMarkerSize()
def fitOnWidget(self):
# Fit the node on the screen
@ -444,6 +521,39 @@ class DirectCameraControl(PandaObject):
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()

View File

@ -86,6 +86,45 @@ def ROUND_TO(value, divisor):
return round(value/float(divisor)) * divisor
def ROUND_INT(val):
return int(round(val))
def CLAMP(val, min, max):
if val < min:
return min
elif val > max:
return max
else:
return val
def getNearProjectionPoint(nodePath):
# Find the position of the projection of the specified node path
# on the near plane
origin = nodePath.getPos(direct.camera)
# project this onto near plane
if origin[1] != 0.0:
return origin * (direct.dr.near / origin[1])
else:
# Object is coplaner with camera, just return something reasonable
return Point3(0, direct.dr.near, 0)
def getScreenXY(nodePath):
# Where does the node path's projection fall on the near plane
nearVec = getNearProjectionPoint(nodePath)
# Clamp these coordinates to visible screen
nearX = CLAMP(nearVec[0], direct.dr.left, direct.dr.right)
nearY = CLAMP(nearVec[2], direct.dr.bottom, direct.dr.top)
# What percentage of the distance across the screen is this?
percentX = (nearX - direct.dr.left)/direct.dr.nearWidth
percentY = (nearY - direct.dr.bottom)/direct.dr.nearHeight
# Map this percentage to the same -1 to 1 space as the mouse
screenXY = Vec3((2 * percentX) - 1.0,nearVec[1],(2 * percentY) - 1.0)
# Return the resulting value
return screenXY
def getCrankAngle(center):
# Used to compute current angle of mouse (relative to the coa's
# origin) in screen space
x = direct.dr.mouseX - center[0]
y = direct.dr.mouseY - center[2]
return (180 + rad2Deg(math.atan2(y,x)))
# Set direct drawing style for an object
# Never light object or draw in wireframe

View File

@ -28,6 +28,7 @@ class DirectManipulationControl(PandaObject):
self.actionEvents = [
['handleMouse1', self.manipulationStart],
['handleMouse1Up', self.manipulationStop],
['space', self.toggleObjectHandlesMode],
['.', self.objectHandles.multiplyScalingFactorBy, 2.0],
['>', self.objectHandles.multiplyScalingFactorBy, 2.0],
[',', self.objectHandles.multiplyScalingFactorBy, 0.5],
@ -137,8 +138,6 @@ class DirectManipulationControl(PandaObject):
# We had been scaling, need to reset object handles
self.objectHandles.transferObjectHandlesScale()
self.fScaling = 0
if self.fSetCoa:
self.objectHandles.manipModeColor()
direct.selected.highlightAll()
self.objectHandles.showAllHandles()
self.objectHandles.hideGuides()
@ -188,6 +187,13 @@ class DirectManipulationControl(PandaObject):
if item in self.unpickable:
self.unpickable.remove(item)
def toggleObjectHandlesMode(self):
self.fSetCoa = 1 - self.fSetCoa
if self.fSetCoa:
self.objectHandles.coaModeColor()
else:
self.objectHandles.manipModeColor()
def removeManipulateObjectTask(self):
taskMgr.removeTasksNamed('manipulateObject')
@ -206,20 +212,10 @@ class DirectManipulationControl(PandaObject):
self.objectHandles.showGuides()
self.objectHandles.hideAllHandles()
self.objectHandles.showHandle(self.constraint)
if self.fSetCoa:
self.objectHandles.coaModeColor()
# Record relationship between selected nodes and widget
direct.selected.getWrtAll()
# hide the bbox of the selected objects during interaction
direct.selected.dehighlightAll()
"""
# Push the undo dcs for the selected objects
direct.undo.push(
(direct.selected, 'dcs'))
"""
# Manipulate the real object with the constraint
# The constraint is passed as the name of the node
self.spawnManipulateObjectTask()
@ -350,13 +346,6 @@ class DirectManipulationControl(PandaObject):
y + self.initY * dr.mouseDeltaY,
z)
def getCrankAngle(self):
# Used to compute current angle of mouse (relative to the widget's
# origin) in screen space
x = direct.dr.mouseX - self.rotationCenter[0]
y = direct.dr.mouseY - self.rotationCenter[2]
return (180 + rad2Deg(math.atan2(y,x)))
def widgetCheck(self,type):
# Utility to see if we are looking at the top or bottom of
# a 2D planar widget or if we are looking at a 2D planar widget
@ -388,27 +377,6 @@ class DirectManipulationControl(PandaObject):
# Check angle between two vectors
return(abs(widgetDir.dot(widgetAxis)) < .2)
def getWidgetsNearProjectionPoint(self):
# Find the position of the projection of the specified node path
# on the near plane
widgetOrigin = direct.widget.getPos(direct.camera)
# project this onto near plane
return widgetOrigin * (direct.dr.near / widgetOrigin[1])
def getScreenXY(self):
# Where does the widget's projection fall on the near plane
nearVec = self.getWidgetsNearProjectionPoint()
# Clamp these coordinates to visible screen
nearX = self.clamp(nearVec[0], direct.dr.left, direct.dr.right)
nearY = self.clamp(nearVec[2], direct.dr.bottom, direct.dr.top)
# What percentage of the distance across the screen is this?
percentX = (nearX - direct.dr.left)/direct.dr.nearWidth
percentY = (nearY - direct.dr.bottom)/direct.dr.nearHeight
# Map this percentage to the same -1 to 1 space as the mouse
screenXY = Vec3((2 * percentX) - 1.0,nearVec[1],(2 * percentY) - 1.0)
# Return the resulting value
return screenXY
def rotate1D(self):
# Constrained 1D rotation about the widget's main axis (X,Y, or Z)
# Rotation depends upon circular motion of the mouse about the
@ -421,11 +389,11 @@ class DirectManipulationControl(PandaObject):
self.fHitInit = 0
self.rotateAxis = self.constraint[:1]
self.fWidgetTop = self.widgetCheck('top?')
self.rotationCenter = self.getScreenXY()
self.lastCrankAngle = self.getCrankAngle()
self.rotationCenter = getScreenXY(direct.widget)
self.lastCrankAngle = getCrankAngle(self.rotationCenter)
# Rotate widget based on how far cursor has swung around origin
newAngle = self.getCrankAngle()
newAngle = getCrankAngle(self.rotationCenter)
deltaAngle = self.lastCrankAngle - newAngle
if self.fWidgetTop:
deltaAngle = -1 * deltaAngle
@ -491,14 +459,6 @@ class DirectManipulationControl(PandaObject):
)
direct.widget.setScale(currScale)
def clamp(self, val, min, max):
if val < min:
return min
elif val > max:
return max
else:
return val
class ObjectHandles(NodePath,PandaObject):
def __init__(self):

View File

@ -82,7 +82,8 @@ class DirectSession(PandaObject):
'escape', 'space', 'delete',
'shift', 'shift-up', 'alt', 'alt-up',
'control', 'control-up',
'page_up', 'page_down',
'page_up', 'page_down', 'tab',
'[', '{', ']', '}',
'b', 'c', 'f', 'l', 's', 't', 'v', 'w']
self.mouseEvents = ['mouse1', 'mouse1-up',
'mouse2', 'mouse2-up',
@ -190,21 +191,27 @@ class DirectSession(PandaObject):
self.downAncestry()
elif input == 'escape':
self.deselectAll()
elif input == 'delete':
self.removeAllSelected()
elif input == 'tab':
self.toggleWidgetVis()
elif input == 'b':
base.toggleBackface()
elif input == 'l':
self.lights.toggle()
elif input == 's':
if self.selected.last:
self.select(self.selected.last)
elif input == 'delete':
self.removeAllSelected()
elif input == 'v':
self.selected.toggleVisAll()
elif input == 'b':
base.toggleBackface()
elif input == 't':
base.toggleTexture()
elif input == 'v':
self.selected.toggleVisAll()
elif input == 'w':
base.toggleWireframe()
elif (input == '[') | (input == '{'):
self.undo()
elif (input == ']') | (input == '}'):
self.redo()
def select(self, nodePath, fMultiselect = 0, fResetAncestry = 1):
dnp = self.selected.select(nodePath, fMultiselect)
@ -219,7 +226,7 @@ class DirectSession(PandaObject):
self.readout.reparentTo(render2d)
self.readout.setText(dnp.name)
# Show the manipulation widget
self.widget.reparentTo(direct.group)
self.reparentWidgetTo('direct')
# Update camera controls coa to this point
# Coa2Camera = Coa2Dnp * Dnp2Camera
mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera)
@ -250,7 +257,7 @@ class DirectSession(PandaObject):
dnp = self.selected.deselect(nodePath)
if dnp:
# Hide the manipulation widget
self.widget.reparentTo(hidden)
self.reparentWidgetTo('hidden')
self.readout.reparentTo(hidden)
self.readout.setText(' ')
taskMgr.removeTasksNamed('followSelectedNodePath')
@ -261,7 +268,7 @@ class DirectSession(PandaObject):
def deselectAll(self):
self.selected.deselectAll()
# Hide the manipulation widget
self.widget.reparentTo(hidden)
self.reparentWidgetTo('hidden')
self.readout.reparentTo(hidden)
self.readout.setText(' ')
taskMgr.removeTasksNamed('followSelectedNodePath')
@ -384,7 +391,7 @@ class DirectSession(PandaObject):
# Now record group
self.undoList.append(undoGroup)
# Truncate list
self.undoList = self.undoList[-5:]
self.undoList = self.undoList[-25:]
# Alert anyone who cares
messenger.send('pushUndo')
if fResetRedo & (nodePathList != []):
@ -413,7 +420,7 @@ class DirectSession(PandaObject):
# Now record redo group
self.redoList.append(redoGroup)
# Truncate list
self.redoList = self.redoList[-5:]
self.redoList = self.redoList[-25:]
# Alert anyone who cares
messenger.send('pushRedo')
@ -462,6 +469,20 @@ class DirectSession(PandaObject):
def hideReadout(self):
self.readout.reparentTo(hidden)
def reparentWidgetTo(self, parent):
if parent == 'direct':
self.widget.reparentTo(direct.group)
self.widgetParent = 'direct'
else:
self.widget.reparentTo(hidden)
self.widgetParent = 'hidden'
def toggleWidgetVis(self):
if self.widgetParent == 'direct':
self.reparentWidgetTo('hidden')
else:
self.reparentWidgetTo('direct')
class DisplayRegionList:
def __init__(self):
self.displayRegionList = []

View File

@ -113,12 +113,46 @@ class Messenger:
"""
self.dict.clear()
def listAllEvents(self):
str = 'Messenger\n'
str = str + '='*50 + '\n'
keys = self.dict.keys()
keys.sort()
for event in keys:
str = str + 'Event: ' + event + '\n'
str = str + '='*50 + '\n'
print str
def __repr__(self):
"""__repr__(self)
Print out the table in a readable format
"""
str = 'Messenger\n'
str = str + '='*50 + '\n'
keys = self.dict.keys()
keys.sort()
for event in keys:
acceptorDict = self.dict[event]
str = str + 'Event: ' + event + '\n'
for object in acceptorDict.keys():
method, extraArgs, persistent = acceptorDict[object]
className = object.__class__.__name__
methodName = method.__name__
str = (str + '\t' +
'Acceptor: ' + className + ' instance' + '\n\t' +
'Method: ' + methodName + '\n\t' +
'Extra Args: ' + `extraArgs` + '\n\t' +
'Persistent: ' + `persistent` + '\n\n'
)
str = str + '='*50 + '\n'
return str
def __reprehensible__(self):
"""__repr__(self)
Old way to print out the table in a readable format
"""
str = 'Messenger\n'
str = str + '='*50 + '\n'
for event in self.dict.keys():
acceptorDict = self.dict[event]
str = str + event + '\n'
@ -129,3 +163,7 @@ class Messenger:
return str