DirectCameraControl.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. from PandaObject import *
  2. from DirectGeometry import *
  3. CAM_MOVE_DURATION = 1.0
  4. COA_MARKER_SF = 0.0075
  5. Y_AXIS = Vec3(0,1,0)
  6. class DirectCameraControl(PandaObject):
  7. def __init__(self):
  8. # Create the grid
  9. self.orthoViewRoll = 0.0
  10. self.lastView = 0
  11. self.coa = Point3(0,100,0)
  12. self.coaDist = 100
  13. self.coaMarker = loader.loadModel('models/misc/sphere')
  14. self.coaMarker.setName('DirectCameraCOAMarker')
  15. self.coaMarker.setColor(1,0,0)
  16. self.coaMarker.setPos(0,0,0)
  17. useDirectRenderStyle(self.coaMarker)
  18. self.coaMarkerPos = Point3(0)
  19. self.camManipRef = direct.group.attachNewNode('camManipRef')
  20. t = CAM_MOVE_DURATION
  21. self.actionEvents = [
  22. ['handleMouse2', self.mouseFlyStart],
  23. ['handleMouse2Up', self.mouseFlyStop],
  24. ['c', self.centerCamIn, 0.5],
  25. ['f', self.fitOnWidget],
  26. ['h', self.homeCam],
  27. ['m', self.moveToFit],
  28. ['u', self.orbitUprightCam],
  29. ['U', self.uprightCam],
  30. [`1`, self.spawnMoveToView, 1],
  31. [`2`, self.spawnMoveToView, 2],
  32. [`3`, self.spawnMoveToView, 3],
  33. [`4`, self.spawnMoveToView, 4],
  34. [`5`, self.spawnMoveToView, 5],
  35. [`6`, self.spawnMoveToView, 6],
  36. [`7`, self.spawnMoveToView, 7],
  37. [`8`, self.spawnMoveToView, 8],
  38. ['9', self.swingCamAboutWidget, -90.0, t],
  39. ['0', self.swingCamAboutWidget, 90.0, t],
  40. ['`', self.removeManipulateCameraTask],
  41. ['=', self.zoomCam, 0.5, t],
  42. ['+', self.zoomCam, 0.5, t],
  43. ['-', self.zoomCam, -2.0, t],
  44. ['_', self.zoomCam, -2.0, t],
  45. ]
  46. def mouseFlyStart(self):
  47. # Record undo point
  48. direct.pushUndo([direct.camera])
  49. # Where are we in the display region?
  50. if ((abs(direct.dr.mouseX) < 0.9) & (abs(direct.dr.mouseY) < 0.9)):
  51. # MOUSE IS IN CENTRAL REGION
  52. # Hide the marker for this kind of motion
  53. self.coaMarker.hide()
  54. # Check for a hit point based on
  55. # current mouse position
  56. # And then spawn task to determine mouse mode
  57. numEntries = direct.iRay.pickGeom(
  58. render,direct.dr.mouseX,direct.dr.mouseY)
  59. # Then filter out hidden nodes from entry list
  60. indexList = []
  61. for i in range(0,numEntries):
  62. entry = direct.iRay.cq.getEntry(i)
  63. node = entry.getIntoNode()
  64. if node.isHidden():
  65. pass
  66. else:
  67. # Not one of the widgets, use it
  68. indexList.append(i)
  69. coa = Point3(0)
  70. if(indexList):
  71. # Grab first point (it should be the closest)
  72. minPt = indexList[0]
  73. # Find hit point in camera's space
  74. hitPt = direct.iRay.camToHitPt(minPt)
  75. coa.set(hitPt[0],hitPt[1],hitPt[2])
  76. coaDist = Vec3(coa - ZERO_POINT).length()
  77. # Handle case of bad coa point (too close or too far)
  78. if ((coaDist < (1.1 * direct.dr.near)) |
  79. (coaDist > direct.dr.far)):
  80. # Just use existing point
  81. coa.assign(self.coaMarker.getPos(direct.camera))
  82. coaDist = Vec3(coa - ZERO_POINT).length()
  83. if coaDist < (1.1 * direct.dr.near):
  84. coa.set(0,100,0)
  85. coaDist = 100
  86. else:
  87. # If no intersection point:
  88. # Use existing point
  89. coa.assign(self.coaMarker.getPos(direct.camera))
  90. coaDist = Vec3(coa - ZERO_POINT).length()
  91. # Check again its not to close
  92. if coaDist < (1.1 * direct.dr.near):
  93. coa.set(0,100,0)
  94. coaDist = 100
  95. # Update coa and marker
  96. self.updateCoa(coa, coaDist)
  97. # Start manipulation
  98. self.spawnXZTranslateOrHPanYZoom()
  99. # END MOUSE IN CENTRAL REGION
  100. else:
  101. if ((abs(direct.dr.mouseX) > 0.9) & (abs(direct.dr.mouseY) > 0.9)):
  102. # Mouse is in corners, spawn roll task
  103. self.spawnMouseRollTask()
  104. else:
  105. # Mouse is in outer frame, spawn mouseRotateTask
  106. self.spawnMouseRotateTask()
  107. def mouseFlyStop(self):
  108. taskMgr.removeTasksNamed('manipulateCamera')
  109. # Show the marker
  110. self.coaMarker.show()
  111. # Resize it
  112. self.updateCoaMarkerSize()
  113. def spawnXZTranslateOrHPanYZoom(self):
  114. # Kill any existing tasks
  115. taskMgr.removeTasksNamed('manipulateCamera')
  116. # Spawn the new task
  117. t = Task.Task(self.XZTranslateOrHPanYZoomTask)
  118. # For HPanYZoom
  119. t.zoomSF = Vec3(self.coa).length()
  120. taskMgr.spawnTaskNamed(t, 'manipulateCamera')
  121. def spawnXZTranslateOrHPPan(self):
  122. # Kill any existing tasks
  123. taskMgr.removeTasksNamed('manipulateCamera')
  124. # Spawn new task
  125. taskMgr.spawnMethodNamed(self.XZTranslateOrHPPanTask,
  126. 'manipulateCamera')
  127. def spawnXZTranslate(self):
  128. # Kill any existing tasks
  129. taskMgr.removeTasksNamed('manipulateCamera')
  130. # Spawn new task
  131. taskMgr.spawnMethodNamed(self.XZTranslateTask, 'manipulateCamera')
  132. def spawnHPanYZoom(self):
  133. # Kill any existing tasks
  134. taskMgr.removeTasksNamed('manipulateCamera')
  135. # Spawn new task
  136. t = Task.Task(self.HPanYZoomTask)
  137. t.zoomSF = Vec3(self.coa).length()
  138. taskMgr.spawnTaskNamed(t, 'manipulateCamera')
  139. def spawnHPPan(self):
  140. # Kill any existing tasks
  141. taskMgr.removeTasksNamed('manipulateCamera')
  142. # Spawn new task
  143. taskMgr.spawnMethodNamed(self.HPPanTask, 'manipulateCamera')
  144. def XZTranslateOrHPanYZoomTask(self, state):
  145. if direct.fShift | direct.fControl:
  146. return self.HPanYZoomTask(state)
  147. else:
  148. return self.XZTranslateTask(state)
  149. def XZTranslateOrHPPanTask(self, state):
  150. if direct.fShift:
  151. # Panning action
  152. return self.HPPanTask(state)
  153. else:
  154. # Translation action
  155. return self.XZTranslateTask(state)
  156. def XZTranslateTask(self,state):
  157. coaDist = Vec3(self.coaMarker.getPos(direct.camera)).length()
  158. xlateSF = (coaDist / direct.dr.near)
  159. direct.camera.setPos(direct.camera,
  160. (-0.5 * direct.dr.mouseDeltaX *
  161. direct.dr.nearWidth *
  162. xlateSF),
  163. 0.0,
  164. (-0.5 * direct.dr.mouseDeltaY *
  165. direct.dr.nearHeight *
  166. xlateSF))
  167. return Task.cont
  168. def HPanYZoomTask(self,state):
  169. if direct.fShift:
  170. moveDir = Vec3(self.coaMarker.getPos(direct.camera))
  171. # If marker is behind camera invert vector
  172. if moveDir[1] < 0.0:
  173. moveDir.assign(moveDir * -1)
  174. moveDir.normalize()
  175. else:
  176. moveDir = Vec3(Y_AXIS)
  177. moveDir.assign(moveDir * (-2.0 * direct.dr.mouseDeltaY *
  178. state.zoomSF))
  179. direct.camera.setPosHpr(direct.camera,
  180. moveDir[0],
  181. moveDir[1],
  182. moveDir[2],
  183. (0.5 * direct.dr.mouseDeltaX *
  184. direct.dr.fovH),
  185. 0.0, 0.0)
  186. return Task.cont
  187. def HPPanTask(self, state):
  188. direct.camera.setHpr(direct.camera,
  189. (0.5 * direct.dr.mouseDeltaX *
  190. direct.dr.fovH),
  191. (-0.5 * direct.dr.mouseDeltaY *
  192. direct.dr.fovV),
  193. 0.0)
  194. return Task.cont
  195. def spawnMouseRotateTask(self):
  196. # Kill any existing tasks
  197. taskMgr.removeTasksNamed('manipulateCamera')
  198. # Set at markers position in render coordinates
  199. self.camManipRef.setPos(self.coaMarkerPos)
  200. self.camManipRef.setHpr(direct.camera, ZERO_POINT)
  201. t = Task.Task(self.mouseRotateTask)
  202. if abs(direct.dr.mouseX) > 0.9:
  203. t.constrainedDir = 'y'
  204. else:
  205. t.constrainedDir = 'x'
  206. taskMgr.spawnTaskNamed(t, 'manipulateCamera')
  207. def mouseRotateTask(self, state):
  208. # If moving outside of center, ignore motion perpendicular to edge
  209. if ((state.constrainedDir == 'y') & (abs(direct.dr.mouseX) > 0.9)):
  210. deltaX = 0
  211. deltaY = direct.dr.mouseDeltaY
  212. elif ((state.constrainedDir == 'x') & (abs(direct.dr.mouseY) > 0.9)):
  213. deltaX = direct.dr.mouseDeltaX
  214. deltaY = 0
  215. else:
  216. deltaX = direct.dr.mouseDeltaX
  217. deltaY = direct.dr.mouseDeltaY
  218. if direct.fShift:
  219. direct.camera.setHpr(direct.camera,
  220. (deltaX * direct.dr.fovH),
  221. (-deltaY * direct.dr.fovV),
  222. 0.0)
  223. self.camManipRef.setPos(self.coaMarkerPos)
  224. self.camManipRef.setHpr(direct.camera, ZERO_POINT)
  225. else:
  226. wrtMat = direct.camera.getMat( self.camManipRef )
  227. self.camManipRef.setHpr(self.camManipRef,
  228. (-1 * deltaX * 180.0),
  229. (deltaY * 180.0),
  230. 0.0)
  231. direct.camera.setMat(self.camManipRef, wrtMat)
  232. return Task.cont
  233. def spawnMouseRollTask(self):
  234. # Kill any existing tasks
  235. taskMgr.removeTasksNamed('manipulateCamera')
  236. # Set at markers position in render coordinates
  237. self.camManipRef.setPos(self.coaMarkerPos)
  238. self.camManipRef.setHpr(direct.camera, ZERO_POINT)
  239. t = Task.Task(self.mouseRollTask)
  240. t.coaCenter = getScreenXY(self.coaMarker)
  241. t.lastAngle = getCrankAngle(t.coaCenter)
  242. t.wrtMat = direct.camera.getMat( self.camManipRef )
  243. taskMgr.spawnTaskNamed(t, 'manipulateCamera')
  244. def mouseRollTask(self, state):
  245. wrtMat = state.wrtMat
  246. angle = getCrankAngle(state.coaCenter)
  247. deltaAngle = angle - state.lastAngle
  248. state.lastAngle = angle
  249. self.camManipRef.setHpr(self.camManipRef, 0, 0, -deltaAngle)
  250. direct.camera.setMat(self.camManipRef, wrtMat)
  251. return Task.cont
  252. def updateCoa(self, cam2point, coaDist = None):
  253. self.coa.set(cam2point[0], cam2point[1], cam2point[2])
  254. if coaDist:
  255. self.coaDist = coaDist
  256. else:
  257. self.coaDist = Vec3(self.coa - ZERO_POINT).length()
  258. # Place the marker in render space
  259. self.coaMarker.setPos(direct.camera,self.coa)
  260. # Resize it
  261. self.updateCoaMarkerSize(coaDist)
  262. # Record marker pos in render space
  263. self.coaMarkerPos.assign(self.coaMarker.getPos())
  264. def updateCoaMarkerSizeOnDeath(self, state):
  265. # Needed because tasks pass in state as first arg
  266. self.updateCoaMarkerSize()
  267. def updateCoaMarkerSize(self, coaDist = None):
  268. if not coaDist:
  269. coaDist = Vec3(self.coaMarker.getPos( direct.camera )).length()
  270. self.coaMarker.setScale(COA_MARKER_SF * coaDist *
  271. math.tan(deg2Rad(direct.dr.fovV)))
  272. def homeCam(self):
  273. # Record undo point
  274. direct.pushUndo([direct.camera])
  275. direct.camera.setMat(Mat4.identMat())
  276. # Resize coa marker
  277. self.updateCoaMarkerSize()
  278. def uprightCam(self):
  279. taskMgr.removeTasksNamed('manipulateCamera')
  280. # Record undo point
  281. direct.pushUndo([direct.camera])
  282. # Pitch camera till upright
  283. currH = direct.camera.getH()
  284. direct.camera.lerpHpr(currH, 0, 0,
  285. CAM_MOVE_DURATION,
  286. other = render,
  287. blendType = 'easeInOut',
  288. task = 'manipulateCamera')
  289. def orbitUprightCam(self):
  290. taskMgr.removeTasksNamed('manipulateCamera')
  291. # Record undo point
  292. direct.pushUndo([direct.camera])
  293. # Transform camera z axis to render space
  294. mCam2Render = camera.getMat(render)
  295. zAxis = Vec3(mCam2Render.xformVec(Z_AXIS))
  296. zAxis.normalize()
  297. # Compute rotation angle needed to upright cam
  298. orbitAngle = rad2Deg(math.acos(CLAMP(zAxis.dot(Z_AXIS),-1,1)))
  299. # Check angle
  300. if orbitAngle < 0.1:
  301. # Already upright
  302. return
  303. # Compute orthogonal axis of rotation
  304. rotAxis = Vec3(zAxis.cross(Z_AXIS))
  305. rotAxis.normalize()
  306. # Find angle between rot Axis and render X_AXIS
  307. rotAngle = rad2Deg(math.acos(CLAMP(rotAxis.dot(X_AXIS),-1,1)))
  308. # Determine sign or rotation angle
  309. if rotAxis[1] < 0:
  310. rotAngle *= -1
  311. # Position ref CS at coa marker with xaxis aligned with rot axis
  312. self.camManipRef.setPos(self.coaMarker, Vec3(0))
  313. self.camManipRef.setHpr(render, rotAngle, 0, 0)
  314. # Reparent Cam to ref Coordinate system
  315. parent = direct.camera.getParent()
  316. direct.camera.wrtReparentTo(self.camManipRef)
  317. # Rotate ref CS to final orientation
  318. t = self.camManipRef.lerpHpr(rotAngle, orbitAngle, 0,
  319. CAM_MOVE_DURATION,
  320. other = render,
  321. blendType = 'easeInOut',
  322. task = 'manipulateCamera')
  323. # Upon death, reparent Cam to parent
  324. t.parent = parent
  325. t.uponDeath = self.reparentCam
  326. def centerCam(self):
  327. self.centerCamIn(1.0)
  328. def centerCamNow(self):
  329. self.centerCamIn(0.)
  330. def centerCamIn(self, t):
  331. taskMgr.removeTasksNamed('manipulateCamera')
  332. # Record undo point
  333. direct.pushUndo([direct.camera])
  334. # Determine marker location
  335. markerToCam = self.coaMarker.getPos( direct.camera )
  336. dist = Vec3(markerToCam - ZERO_POINT).length()
  337. scaledCenterVec = Y_AXIS * dist
  338. delta = markerToCam - scaledCenterVec
  339. self.camManipRef.setPosHpr(direct.camera, Point3(0), Point3(0))
  340. t = direct.camera.lerpPos(Point3(delta),
  341. CAM_MOVE_DURATION,
  342. other = self.camManipRef,
  343. blendType = 'easeInOut',
  344. task = 'manipulateCamera')
  345. t.uponDeath = self.updateCoaMarkerSizeOnDeath
  346. def zoomCam(self, zoomFactor, t):
  347. taskMgr.removeTasksNamed('manipulateCamera')
  348. # Record undo point
  349. direct.pushUndo([direct.camera])
  350. # Find a point zoom factor times the current separation
  351. # of the widget and cam
  352. zoomPtToCam = self.coaMarker.getPos(direct.camera) * zoomFactor
  353. # Put a target nodePath there
  354. self.camManipRef.setPos(direct.camera, zoomPtToCam)
  355. # Move to that point
  356. t = direct.camera.lerpPos(ZERO_POINT,
  357. CAM_MOVE_DURATION,
  358. other = self.camManipRef,
  359. blendType = 'easeInOut',
  360. task = 'manipulateCamera')
  361. t.uponDeath = self.updateCoaMarkerSizeOnDeath
  362. def spawnMoveToView(self, view):
  363. # Kill any existing tasks
  364. taskMgr.removeTasksNamed('manipulateCamera')
  365. # Record undo point
  366. direct.pushUndo([direct.camera])
  367. # Calc hprOffset
  368. hprOffset = VBase3()
  369. if view == 8:
  370. # Try the next roll angle
  371. self.orthoViewRoll = (self.orthoViewRoll + 90.0) % 360.0
  372. # but use the last view
  373. view = self.lastView
  374. else:
  375. self.orthoViewRoll = 0.0
  376. # Adjust offset based on specified view
  377. if view == 1:
  378. hprOffset.set(180., 0., 0.)
  379. elif view == 2:
  380. hprOffset.set(0., 0., 0.)
  381. elif view == 3:
  382. hprOffset.set(90., 0., 0.)
  383. elif view == 4:
  384. hprOffset.set(-90., 0., 0.)
  385. elif view == 5:
  386. hprOffset.set(0., -90., 0.)
  387. elif view == 6:
  388. hprOffset.set(0., 90., 0.)
  389. elif view == 7:
  390. hprOffset.set(135., -35.264, 0.)
  391. # Position target
  392. self.camManipRef.setPosHpr(self.coaMarker, ZERO_VEC,
  393. hprOffset)
  394. # Scale center vec by current distance to target
  395. offsetDistance = Vec3(direct.camera.getPos(self.camManipRef) -
  396. ZERO_POINT).length()
  397. scaledCenterVec = Y_AXIS * (-1.0 * offsetDistance)
  398. # Now put the camManipRef at that point
  399. self.camManipRef.setPosHpr(self.camManipRef,
  400. scaledCenterVec,
  401. ZERO_VEC)
  402. # Record view for next time around
  403. self.lastView = view
  404. t = direct.camera.lerpPosHpr(ZERO_POINT,
  405. VBase3(0,0,self.orthoViewRoll),
  406. CAM_MOVE_DURATION,
  407. other = self.camManipRef,
  408. blendType = 'easeInOut',
  409. task = 'manipulateCamera')
  410. t.uponDeath = self.updateCoaMarkerSizeOnDeath
  411. def swingCamAboutWidget(self, degrees, t):
  412. # Remove existing camera manipulation task
  413. taskMgr.removeTasksNamed('manipulateCamera')
  414. # Record undo point
  415. direct.pushUndo([direct.camera])
  416. # Coincident with widget
  417. self.camManipRef.setPos(self.coaMarker, ZERO_POINT)
  418. # But aligned with render space
  419. self.camManipRef.setHpr(ZERO_POINT)
  420. parent = direct.camera.getParent()
  421. direct.camera.wrtReparentTo(self.camManipRef)
  422. manipTask = self.camManipRef.lerpHpr(VBase3(degrees,0,0),
  423. CAM_MOVE_DURATION,
  424. blendType = 'easeInOut',
  425. task = 'manipulateCamera')
  426. # Upon death, reparent Cam to parent
  427. manipTask.parent = parent
  428. manipTask.uponDeath = self.reparentCam
  429. def reparentCam(self, state):
  430. direct.camera.wrtReparentTo(state.parent)
  431. self.updateCoaMarkerSize()
  432. def fitOnWidget(self):
  433. # Fit the node on the screen
  434. # stop any ongoing tasks
  435. taskMgr.removeTasksNamed('manipulateCamera')
  436. # How big is the node?
  437. nodeScale = direct.widget.scalingNode.getScale(render)
  438. maxScale = max(nodeScale[0],nodeScale[1],nodeScale[2])
  439. maxDim = min(direct.dr.nearWidth, direct.dr.nearHeight)
  440. # At what distance does the object fill 30% of the screen?
  441. # Assuming radius of 1 on widget
  442. camY = direct.dr.near * (2.0 * maxScale)/(0.3 * maxDim)
  443. # What is the vector through the center of the screen?
  444. centerVec = Y_AXIS * camY
  445. # Where is the node relative to the viewpoint
  446. vWidget2Camera = direct.widget.getPos(direct.camera)
  447. # How far do you move the camera to be this distance from the node?
  448. deltaMove = vWidget2Camera - centerVec
  449. # Move a target there
  450. self.camManipRef.setPos(direct.camera, deltaMove)
  451. parent = direct.camera.getParent()
  452. direct.camera.wrtReparentTo(self.camManipRef)
  453. fitTask = direct.camera.lerpPos(Point3(0,0,0),
  454. CAM_MOVE_DURATION,
  455. blendType = 'easeInOut',
  456. task = 'manipulateCamera')
  457. # Upon death, reparent Cam to parent
  458. fitTask.parent = parent
  459. fitTask.uponDeath = self.reparentCam
  460. def moveToFit(self):
  461. # How bit is the active widget?
  462. widgetScale = direct.widget.scalingNode.getScale(render)
  463. maxScale = max(widgetScale[0], widgetScale[1], widgetScale[2])
  464. # At what distance does the widget fill 50% of the screen?
  465. camY = ((2 * direct.dr.near * (1.5 * maxScale)) /
  466. min(direct.dr.nearWidth, direct.dr.nearHeight))
  467. # Find a point this distance along the Y axis
  468. # MRM: This needs to be generalized to support non uniform frusta
  469. centerVec = Y_AXIS * camY
  470. # Before moving, record the relationship between the selected nodes
  471. # and the widget, so that this can be maintained
  472. direct.selected.getWrtAll()
  473. # Push state onto undo stack
  474. direct.pushUndo(direct.selected)
  475. # Remove the task to keep the widget attached to the object
  476. taskMgr.removeTasksNamed('followSelectedNodePath')
  477. # Spawn a task to keep the selected objects with the widget
  478. taskMgr.spawnMethodNamed(self.stickToWidgetTask, 'stickToWidget')
  479. # Spawn a task to move the widget
  480. t = direct.widget.lerpPos(Point3(centerVec),
  481. CAM_MOVE_DURATION,
  482. other = direct.camera,
  483. blendType = 'easeInOut',
  484. task = 'moveToFitTask')
  485. t.uponDeath = lambda state: taskMgr.removeTasksNamed('stickToWidget')
  486. def stickToWidgetTask(self, state):
  487. # Move the objects with the widget
  488. direct.selected.moveWrtWidgetAll()
  489. # Continue
  490. return Task.cont
  491. def enableMouseFly(self):
  492. # disable C++ fly interface
  493. base.disableMouse()
  494. # Enable events
  495. for event in self.actionEvents:
  496. self.accept(event[0], event[1], extraArgs = event[2:])
  497. # Show marker
  498. self.coaMarker.reparentTo(direct.group)
  499. def disableMouseFly(self):
  500. # Hide the marker
  501. self.coaMarker.reparentTo(hidden)
  502. # Ignore events
  503. for event in self.actionEvents:
  504. self.ignore(event[0])
  505. def removeManipulateCameraTask(self):
  506. taskMgr.removeTasksNamed('manipulateCamera')