DirectSession.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. import math
  2. from panda3d.core import *
  3. from .DirectUtil import *
  4. from direct.showbase.DirectObject import DirectObject
  5. from direct.showbase.BulletinBoardGlobal import bulletinBoard as bboard
  6. from direct.task import Task
  7. from .DirectGlobals import DIRECT_NO_MOD
  8. from .DirectCameraControl import DirectCameraControl
  9. from .DirectManipulation import DirectManipulationControl
  10. from .DirectSelection import SelectionRay, COA_ORIGIN, SelectedNodePaths
  11. from .DirectGrid import DirectGrid
  12. #from DirectGeometry import *
  13. from .DirectLights import DirectLights
  14. from direct.cluster.ClusterClient import createClusterClient, DummyClusterClient
  15. from direct.cluster.ClusterServer import ClusterServer
  16. ## from direct.tkpanels import Placer
  17. ## from direct.tkwidgets import Slider
  18. ## from direct.tkwidgets import SceneGraphExplorer
  19. from direct.gui import OnscreenText
  20. from direct.interval.IntervalGlobal import *
  21. class DirectSession(DirectObject):
  22. # post this to the bboard to make sure DIRECT doesn't turn on
  23. DIRECTdisablePost = 'disableDIRECT'
  24. def __init__(self):
  25. # Establish a global pointer to the direct object early on
  26. # so dependant classes can access it in their code
  27. __builtins__["direct"] = base.direct = self
  28. # These come early since they are used later on
  29. self.group = render.attachNewNode('DIRECT')
  30. self.font = TextNode.getDefaultFont()
  31. self.fEnabled = 0
  32. self.fEnabledLight = 0
  33. self.fScaleWidgetByCam = 0 # [gjeon] flag for scaling widget by distance from the camera
  34. self.fIgnoreDirectOnlyKeyMap = 0 # [gjeon] to skip old direct controls in new LE
  35. self.drList = DisplayRegionList()
  36. self.iRayList = [x.iRay for x in self.drList]
  37. self.dr = self.drList[0]
  38. self.win = base.win
  39. self.camera = base.camera
  40. self.cam = base.cam
  41. self.camNode = base.camNode
  42. self.trueCamera = self.camera
  43. self.iRay = self.dr.iRay
  44. self.coaMode = COA_ORIGIN
  45. self.cameraControl = DirectCameraControl()
  46. self.manipulationControl = DirectManipulationControl()
  47. self.useObjectHandles()
  48. self.grid = DirectGrid()
  49. self.grid.disable()
  50. self.lights = DirectLights(base.direct.group)
  51. # Create some default lights
  52. self.lights.createDefaultLights()
  53. # But turn them off
  54. self.lights.allOff()
  55. # Initialize the collection of selected nodePaths
  56. self.selected = SelectedNodePaths()
  57. # Ancestry of currently selected object
  58. self.ancestry = []
  59. self.ancestryIndex = 0
  60. self.activeParent = None
  61. self.selectedNPReadout = OnscreenText.OnscreenText(
  62. pos = (0.1, 0.1), bg=Vec4(0, 0, 0, .2), style=3,
  63. fg = (1, 1, 1, 1), scale = 0.05, align = TextNode.ALeft,
  64. mayChange = 1, font = self.font)
  65. # Make sure readout is never lit or drawn in wireframe
  66. useDirectRenderStyle(self.selectedNPReadout)
  67. self.selectedNPReadout.reparentTo(hidden)
  68. self.activeParentReadout = OnscreenText.OnscreenText(
  69. pos = (0.1, 0.16), bg=Vec4(0, 0, 0, .2), style = 3,
  70. fg = (1, 1, 1, 1), scale = 0.05, align = TextNode.ALeft,
  71. mayChange = 1, font = self.font)
  72. # Make sure readout is never lit or drawn in wireframe
  73. useDirectRenderStyle(self.activeParentReadout)
  74. self.activeParentReadout.reparentTo(hidden)
  75. self.directMessageReadout = OnscreenText.OnscreenText(
  76. pos = (0.1, -0.1), bg=Vec4(0, 0, 0, .2), style = 3,
  77. fg = (1, 1, 1, 1), scale = 0.05, align = TextNode.ALeft,
  78. mayChange = 1, font = self.font)
  79. # Make sure readout is never lit or drawn in wireframe
  80. useDirectRenderStyle(self.directMessageReadout)
  81. self.directMessageReadout.reparentTo(hidden)
  82. # Create a vrpn client vrpn-server or default
  83. self.deviceManager = None
  84. self.joybox = None
  85. self.radamec = None
  86. self.fastrak = []
  87. if ConfigVariableBool('want-vrpn', False):
  88. from direct.directdevices import DirectDeviceManager
  89. self.deviceManager = DirectDeviceManager.DirectDeviceManager()
  90. # Automatically create any devices specified in config file
  91. joybox = ConfigVariableString('vrpn-joybox-device', '').value
  92. radamec = ConfigVariableString('vrpn-radamec-device', '').value
  93. fastrak = ConfigVariableString('vrpn-fastrak-device', '').value
  94. if joybox:
  95. from direct.directdevices import DirectJoybox
  96. self.joybox = DirectJoybox.DirectJoybox(joybox)
  97. if radamec:
  98. from direct.directdevices import DirectRadamec
  99. self.radamec = DirectRadamec.DirectRadamec(radamec)
  100. if fastrak:
  101. from direct.directdevices import DirectFastrak
  102. # parse string into format device:N where N is the sensor name
  103. fastrak = fastrak.split()
  104. for i in range(len(fastrak))[1:]:
  105. self.fastrak.append(DirectFastrak.DirectFastrak(fastrak[0] + ':' + fastrak[i]))
  106. self.fControl = 0
  107. self.fAlt = 0
  108. self.fShift = 0
  109. self.fMouse1 = 0 # [gjeon] to update alt key information while mouse1 is pressed
  110. self.fMouse2 = 0
  111. self.fMouse3 = 0
  112. self.pos = VBase3()
  113. self.hpr = VBase3()
  114. self.scale = VBase3()
  115. self.hitPt = Point3(0.0)
  116. # Lists for managing undo/redo operations
  117. self.undoList = []
  118. self.redoList = []
  119. # One run through the context task to init everything
  120. self.drList.updateContext()
  121. for dr in self.drList:
  122. dr.camUpdate()
  123. self.actionEvents = [
  124. ['select', self.select],
  125. ['DIRECT-select', self.selectCB],
  126. ['deselect', self.deselect],
  127. ['deselectAll', self.deselectAll],
  128. ['DIRECT-preDeselectAll', self.deselectAllCB],
  129. ['highlightAll', self.selected.highlightAll],
  130. ['preRemoveNodePath', self.deselect],
  131. # Scene graph explorer functions
  132. ['SGE_Select', self.select],
  133. ['SGE_Deselect', self.deselect],
  134. ['SGE_Set Reparent Target', self.setActiveParent],
  135. ['SGE_Reparent', self.reparent],
  136. ['SGE_WRT Reparent', lambda np, s=self: s.reparent(np, fWrt = 1)],
  137. ['SGE_Flash', self.flash],
  138. ['SGE_Isolate', self.isolate],
  139. ['SGE_Toggle Vis', self.toggleVis],
  140. ['SGE_Show All', self.showAllDescendants],
  141. ['SGE_Fit', self.fitOnNodePath],
  142. ['SGE_Delete', self.removeNodePath],
  143. ['SGE_Set Name', self.getAndSetName],
  144. ['DIRECT-delete', self.removeAllSelected],
  145. ['DIRECT-Undo', self.undo],
  146. ['DIRECT-Redo', self.redo],
  147. ['DIRECT-OOBE', self.oobe],
  148. ['DIRECT-toggleWidgetVis', self.toggleWidgetVis],
  149. ['DIRECT-toggleWireframe', base.toggleWireframe],
  150. ['DIRECT-toggleVisAll', self.selected.toggleVisAll],
  151. ['DIRECT-toggleTexture', base.toggleTexture],
  152. ['DIRECT-upAncestry', self.upAncestry],
  153. ['DIRECT-downAncestry', self.downAncestry],
  154. ['DIRECT-toggleBackface', base.toggleBackface],
  155. ['DIRECT-flash', self.flash],
  156. ['DIRECT-toggleLigths', self.lights.toggle],
  157. ['DIRECT-toggleCOALock', self.cameraControl.toggleCOALock],
  158. ['DIRECT-setActiveParent', self.doSetActiveParent],
  159. ['DIRECT-doWrtReparent', self.doWrtReparent],
  160. ['DIRECT-doReparent', self.doReparent],
  161. ['DIRECT-doSelect', self.doSelect],
  162. ]
  163. if base.wantTk:
  164. from direct.tkpanels import Placer
  165. from direct.tkwidgets import Slider
  166. from direct.tkwidgets import SceneGraphExplorer
  167. self.actionEvents.extend([
  168. ['SGE_Place', Placer.place],
  169. ['SGE_Set Color', Slider.rgbPanel],
  170. ['SGE_Explore', SceneGraphExplorer.explore],])
  171. self.modifierEvents = ['control', 'control-up', 'control-repeat',
  172. 'shift', 'shift-up', 'shift-repeat',
  173. 'alt', 'alt-up', 'alt-repeat',
  174. ]
  175. keyList = [chr(i) for i in range(97, 123)]
  176. keyList.extend([chr(i) for i in range(48, 58)])
  177. keyList.extend(["`", "-", "=", "[", "]", ";", "'", ",", ".", "/", "\\"])
  178. self.specialKeys = ['escape', 'delete', 'page_up', 'page_down', 'enter']
  179. def addCtrl(a):
  180. return "control-%s"%a
  181. def addShift(a):
  182. return "shift-%s"%a
  183. self.keyEvents = keyList[:]
  184. self.keyEvents.extend(list(map(addCtrl, keyList)))
  185. self.keyEvents.extend(list(map(addShift, keyList)))
  186. self.keyEvents.extend(self.specialKeys)
  187. self.mouseEvents = ['mouse1', 'mouse1-up',
  188. 'shift-mouse1', 'shift-mouse1-up',
  189. 'control-mouse1', 'control-mouse1-up',
  190. 'alt-mouse1', 'alt-mouse1-up',
  191. 'mouse2', 'mouse2-up',
  192. 'shift-mouse2', 'shift-mouse2-up',
  193. 'control-mouse2', 'control-mouse2-up',
  194. 'alt-mouse2', 'alt-mouse2-up',
  195. 'mouse3', 'mouse3-up',
  196. 'shift-mouse3', 'shift-mouse3-up',
  197. 'control-mouse3', 'control-mouse3-up',
  198. 'alt-mouse3', 'alt-mouse3-up',
  199. ]
  200. self.directOnlyKeyMap = {
  201. 'u': ('Orbit Upright Camera', 'DIRECT-orbitUprightCam'),
  202. 'shift-u': ('Upright Camera', 'DIRECT-uprightCam'),
  203. '1': ('Move Camera to View 1', 'DIRECT-spwanMoveToView-1'),
  204. '2': ('Move Camera to View 2', 'DIRECT-spwanMoveToView-2'),
  205. '3': ('Move Camera to View 3', 'DIRECT-spwanMoveToView-3'),
  206. '4': ('Move Camera to View 4', 'DIRECT-spwanMoveToView-4'),
  207. '5': ('Move Camera to View 5', 'DIRECT-spwanMoveToView-5'),
  208. '6': ('Move Camera to View 6', 'DIRECT-spwanMoveToView-6'),
  209. '7': ('Move Camera to View 7', 'DIRECT-spwanMoveToView-7'),
  210. '8': ('Move Camera to View 8', 'DIRECT-spwanMoveToView-8'),
  211. '9': ('Rotate Camera About widget 90 degrees Counterclockwise', 'DIRECT-swingCamAboutWidget-0'),
  212. '0': ('Rotate Camera About widget 90 degrees Clockwise', 'DIRECT-swingCamAboutWidget-1'),
  213. '`': ('Remove ManipulateCameraTask', 'DIRECT-removeManipulateCameraTask'),
  214. '=': ('Zoom In', 'DIRECT-zoomInCam'),
  215. 'shift-=': ('Zoom In', 'DIRECT-zoomInCam'),
  216. 'shift-_': ('Zoom Out', 'DIRECT-zoomOutCam'),
  217. '-': ('Zoom Out', 'DIRECT-zoomOutCam'),
  218. 'o': ('Toggle OOBE', 'DIRECT-OOBE'),
  219. '[': ('DIRECT-Undo', 'DIRECT-Undo'),
  220. 'shift-[': ('DIRECT-Undo', 'DIRECT-Undo'),
  221. ']': ('DIRECT-Redo', 'DIRECT-Redo'),
  222. 'shift-]': ('DIRECT-Redo', 'DIRECT-Redo'),
  223. }
  224. self.hotKeyMap = {
  225. 'c': ('Center Camera', 'DIRECT-centerCamIn'),
  226. 'f': ('Fit on Widget', 'DIRECT-fitOnWidget'),
  227. 'h': ('Move Camera to ', 'DIRECT-homeCam'),
  228. 'shift-v': ('Toggle Marker', 'DIRECT-toggleMarkerVis'),
  229. 'm': ('Move to fit', 'DIRECT-moveToFit'),
  230. 'n': ('Pick Next COA', 'DIRECT-pickNextCOA'),
  231. 'delete': ('Delete', 'DIRECT-delete'),
  232. '.': ('Scale Up Widget', 'DIRECT-widgetScaleUp'),
  233. ',': ('Scale Down Widget', 'DIRECT-widgetScaleDown'),
  234. 'page_up': ('Up Ancestry', 'DIRECT-upAncestry'),
  235. 'page_down': ('Down Ancestry', 'DIRECT-downAncestry'),
  236. 'escape': ('Deselect All', 'deselectAll'),
  237. 'v': ('Toggle Manipulating Widget', 'DIRECT-toggleWidgetVis'),
  238. 'b': ('Toggle Backface', 'DIRECT-toggleBackface'),
  239. 'control-f': ('Flash', 'DIRECT-flash'),
  240. 'l': ('Toggle lights', 'DIRECT-toggleLigths'),
  241. 'shift-l': ('Toggle COA Lock', 'DIRECT-toggleCOALock'),
  242. 'p': ('Set Active Parent', 'DIRECT-setActiveParent'),
  243. 'r': ('Wrt Reparent', 'DIRECT-doWrtReparent'),
  244. 'shift-r': ('Reparent', 'DIRECT-doReparent'),
  245. 's': ('Select', 'DIRECT-doSelect'),
  246. 't': ('Toggle Textures', 'DIRECT-toggleTexture'),
  247. 'shift-a': ('Toggle Vis all', 'DIRECT-toggleVisAll'),
  248. 'w': ('Toggle Wireframe', 'DIRECT-toggleWireframe'),
  249. 'control-z': ('Undo', 'LE-Undo'),
  250. 'shift-z' : ('Redo', 'LE-Redo'),
  251. 'control-d': ('Duplicate', 'LE-Duplicate'),
  252. 'control-l': ('Make Live', 'LE-MakeLive'),
  253. 'control-n': ('New Scene', 'LE-NewScene'),
  254. 'control-s': ('Save Scene', 'LE-SaveScene'),
  255. 'control-o': ('Open Scene', 'LE-OpenScene'),
  256. 'control-q': ('Quit', 'LE-Quit'),
  257. }
  258. self.speicalKeyMap = {
  259. 'enter': 'DIRECT-enter',
  260. }
  261. self.passThroughKeys = ['v','b','l','p', 'r', 'shift-r', 's', 't','shift-a', 'w']
  262. if base.wantTk:
  263. from direct.tkpanels import DirectSessionPanel
  264. self.panel = DirectSessionPanel.DirectSessionPanel(parent = base.tkRoot)
  265. try:
  266. # Has the clusterMode been set externally (i.e. via the
  267. # bootstrap application?
  268. self.clusterMode = clusterMode
  269. except NameError:
  270. # Has the clusterMode been set via a config variable?
  271. self.clusterMode = ConfigVariableString("cluster-mode", '').value
  272. if self.clusterMode == 'client':
  273. self.cluster = createClusterClient()
  274. elif self.clusterMode == 'server':
  275. self.cluster = ClusterServer(base.camera, base.cam)
  276. else:
  277. self.cluster = DummyClusterClient()
  278. __builtins__['cluster'] = self.cluster
  279. def addPassThroughKey(self,key):
  280. self.passThroughKeys.append(key)
  281. def enable(self):
  282. # don't enable DIRECT if someone has posted DIRECTdisablePost
  283. if bboard.has(DirectSession.DIRECTdisablePost):
  284. return
  285. if self.fEnabled:
  286. return
  287. # Make sure old tasks are shut down
  288. self.disable()
  289. # Start all display region context tasks
  290. self.drList.spawnContextTask()
  291. if not self.fEnabledLight:
  292. # Turn on mouse Flying
  293. self.cameraControl.enableMouseFly()
  294. # Turn on object manipulation
  295. self.manipulationControl.enableManipulation()
  296. # Make sure list of selected items is reset
  297. self.selected.reset()
  298. # Accept appropriate hooks
  299. if not self.fEnabledLight:
  300. self.enableKeyEvents()
  301. self.enableMouseEvents()
  302. self.enableActionEvents()
  303. self.enableModifierEvents()
  304. # Set flag
  305. self.fEnabled = 1
  306. def enableLight(self):
  307. self.fEnabledLight = 1
  308. self.enable()
  309. def disable(self):
  310. # Shut down all display region context tasks
  311. self.drList.removeContextTask()
  312. # Turn off camera fly
  313. self.cameraControl.disableMouseFly()
  314. # Turn off object manipulation
  315. self.deselectAll()
  316. self.manipulationControl.disableManipulation()
  317. self.disableKeyEvents()
  318. self.disableModifierEvents()
  319. self.disableMouseEvents()
  320. self.disableActionEvents()
  321. # Kill tasks
  322. taskMgr.remove('flashNodePath')
  323. taskMgr.remove('hideDirectMessage')
  324. taskMgr.remove('hideDirectMessageLater')
  325. # Set flag
  326. self.fEnabled = 0
  327. def toggleDirect(self):
  328. if self.fEnabled:
  329. self.disable()
  330. else:
  331. self.enable()
  332. def minimumConfiguration(self):
  333. # Remove context task
  334. self.drList.removeContextTask()
  335. # Turn off camera fly
  336. self.cameraControl.disableMouseFly()
  337. # Ignore keyboard and action events
  338. self.disableKeyEvents()
  339. self.disableActionEvents()
  340. # But let mouse events pass through
  341. self.enableMouseEvents()
  342. self.enableModifierEvents()
  343. def oobe(self):
  344. # If oobeMode was never set, set it to false and create the
  345. # structures we need to implement OOBE.
  346. if not hasattr(self, 'oobeMode'):
  347. self.oobeMode = 0
  348. self.oobeCamera = hidden.attachNewNode('oobeCamera')
  349. self.oobeVis = base.loader.loadModel('models/misc/camera')
  350. if self.oobeVis:
  351. self.oobeVis.node().setFinal(1)
  352. if self.oobeMode:
  353. # Position a target point to lerp the oobe camera to
  354. base.direct.cameraControl.camManipRef.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
  355. ival = self.oobeCamera.posHprInterval(
  356. 2.0, pos = Point3(0), hpr = Vec3(0),
  357. other = base.direct.cameraControl.camManipRef,
  358. blendType = 'easeInOut')
  359. ival = Sequence(ival, Func(self.endOOBE), name = 'oobeTransition')
  360. ival.start()
  361. else:
  362. # Place camera marker at true camera location
  363. self.oobeVis.reparentTo(self.trueCamera)
  364. # Remove any transformation on the models arc
  365. self.oobeVis.clearMat()
  366. # Make oobeCamera be a sibling of wherever camera is now.
  367. cameraParent = self.camera.getParent()
  368. # Prepare oobe camera
  369. self.oobeCamera.reparentTo(cameraParent)
  370. self.oobeCamera.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
  371. # Put camera under new oobe camera
  372. self.cam.reparentTo(self.oobeCamera)
  373. # Position a target point to lerp the oobe camera to
  374. base.direct.cameraControl.camManipRef.setPos(
  375. self.trueCamera, Vec3(-2, -20, 5))
  376. base.direct.cameraControl.camManipRef.lookAt(self.trueCamera)
  377. ival = self.oobeCamera.posHprInterval(
  378. 2.0, pos = Point3(0), hpr = Vec3(0),
  379. other = base.direct.cameraControl.camManipRef,
  380. blendType = 'easeInOut')
  381. ival = Sequence(ival, Func(self.beginOOBE), name = 'oobeTransition')
  382. ival.start()
  383. def beginOOBE(self):
  384. # Make sure we've reached our final destination
  385. self.oobeCamera.setPosHpr(base.direct.cameraControl.camManipRef, 0, 0, 0, 0, 0, 0)
  386. base.direct.camera = self.oobeCamera
  387. self.oobeMode = 1
  388. def endOOBE(self):
  389. # Make sure we've reached our final destination
  390. self.oobeCamera.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
  391. # Disable OOBE mode.
  392. self.cam.reparentTo(self.trueCamera)
  393. base.direct.camera = self.trueCamera
  394. # Get rid of ancillary node paths
  395. self.oobeVis.reparentTo(hidden)
  396. self.oobeCamera.reparentTo(hidden)
  397. self.oobeMode = 0
  398. def destroy(self):
  399. self.disable()
  400. def reset(self):
  401. self.enable()
  402. # EVENT FUNCTIONS
  403. def enableActionEvents(self):
  404. for event in self.actionEvents:
  405. self.accept(event[0], event[1], extraArgs = event[2:])
  406. def enableModifierEvents(self):
  407. for event in self.modifierEvents:
  408. self.accept(event, self.inputHandler, [event])
  409. def enableKeyEvents(self):
  410. for event in self.keyEvents:
  411. self.accept(event, self.inputHandler, [event])
  412. def enableMouseEvents(self):
  413. for event in self.mouseEvents:
  414. self.accept(event, self.inputHandler, [event])
  415. def disableActionEvents(self):
  416. for event, method in self.actionEvents:
  417. self.ignore(event)
  418. def disableModifierEvents(self):
  419. for event in self.modifierEvents:
  420. self.ignore(event)
  421. def disableKeyEvents(self):
  422. for event in self.keyEvents:
  423. self.ignore(event)
  424. def disableMouseEvents(self):
  425. for event in self.mouseEvents:
  426. self.ignore(event)
  427. def inputHandler(self, input):
  428. if not hasattr(self, 'oobeMode') or self.oobeMode == 0:
  429. # [gjeon] change current camera dr, iRay, mouseWatcher accordingly to support multiple windows
  430. if base.direct.manipulationControl.fMultiView:
  431. # handling orphan events
  432. if self.fMouse1 and 'mouse1' not in input or\
  433. self.fMouse2 and 'mouse2' not in input or\
  434. self.fMouse3 and 'mouse3' not in input:
  435. if input.endswith('-up') or\
  436. input not in self.modifierEvents:
  437. # to handle orphan events
  438. return
  439. if (self.fMouse1 == 0 and 'mouse1-up' in input) or\
  440. (self.fMouse2 == 0 and 'mouse2-up' in input) or\
  441. (self.fMouse3 == 0 and 'mouse3-up' in input):
  442. # to handle orphan events
  443. return
  444. if (self.fMouse1 or self.fMouse2 or self.fMouse3) and\
  445. input[4:7] != base.direct.camera.getName()[:3] and\
  446. input.endswith('-up'):
  447. # to handle orphan events
  448. return
  449. winCtrl = None
  450. possibleWinCtrls = []
  451. for cWinCtrl in base.winControls:
  452. if cWinCtrl.mouseWatcher.node().hasMouse():
  453. possibleWinCtrls.append(cWinCtrl)
  454. if len(possibleWinCtrls) == 1:
  455. winCtrl = possibleWinCtrls[0]
  456. elif len(possibleWinCtrls) > 1:
  457. for cWinCtrl in possibleWinCtrls:
  458. if (input.endswith('-up') and\
  459. not input in self.modifierEvents and\
  460. not input in self.mouseEvents) or\
  461. (input in self.mouseEvents):
  462. if input[4:7] == cWinCtrl.camera.getName()[:3]:
  463. winCtrl = cWinCtrl
  464. else:
  465. if input[4:7] != cWinCtrl.camera.getName()[:3]:
  466. winCtrl = cWinCtrl
  467. if winCtrl is None:
  468. return
  469. if input not in self.modifierEvents:
  470. self.win = winCtrl.win
  471. self.camera = winCtrl.camera
  472. self.trueCamera = self.camera
  473. self.cam = NodePath(winCtrl.camNode)
  474. self.camNode = winCtrl.camNode
  475. if hasattr(winCtrl, 'grid'):
  476. base.direct.grid = winCtrl.grid
  477. base.direct.dr = base.direct.drList[base.camList.index(NodePath(winCtrl.camNode))]
  478. base.direct.iRay = base.direct.dr.iRay
  479. base.mouseWatcher = winCtrl.mouseWatcher
  480. base.mouseWatcherNode = winCtrl.mouseWatcher.node()
  481. base.direct.dr.mouseUpdate()
  482. LE_showInOneCam(self.selectedNPReadout, self.camera.getName())
  483. base.direct.widget = base.direct.manipulationControl.widgetList[base.camList.index(NodePath(winCtrl.camNode))]
  484. input = input[8:] # get rid of camera prefix
  485. if self.fAlt and 'alt' not in input and not input.endswith('-up'):
  486. input = 'alt-' + input
  487. if input.endswith('-repeat'):
  488. input = input[:-7]
  489. # Deal with keyboard and mouse input
  490. if input in self.hotKeyMap:
  491. keyDesc = self.hotKeyMap[input]
  492. messenger.send(keyDesc[1])
  493. elif input in self.speicalKeyMap:
  494. messenger.send(self.speicalKeyMap[input])
  495. elif input in self.directOnlyKeyMap:
  496. if self.fIgnoreDirectOnlyKeyMap:
  497. return
  498. keyDesc = self.directOnlyKeyMap[input]
  499. messenger.send(keyDesc[1])
  500. elif input == 'mouse1-up':
  501. self.fMouse1 = 0 # [gjeon] to update alt key information while mouse1 is pressed
  502. messenger.send('DIRECT-mouse1Up')
  503. elif input.find('mouse1') != -1:
  504. self.fMouse1 = 1 # [gjeon] to update alt key information while mouse1 is pressed
  505. modifiers = self.getModifiers(input, 'mouse1')
  506. messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
  507. elif input == 'mouse2-up':
  508. self.fMouse2 = 0
  509. messenger.send('DIRECT-mouse2Up')
  510. elif input.find('mouse2') != -1:
  511. self.fMouse2 = 1
  512. modifiers = self.getModifiers(input, 'mouse2')
  513. messenger.send('DIRECT-mouse2', sentArgs = [modifiers])
  514. elif input == 'mouse3-up':
  515. self.fMouse3 = 0
  516. messenger.send('DIRECT-mouse3Up')
  517. elif input.find('mouse3') != -1:
  518. self.fMouse3 = 1
  519. modifiers = self.getModifiers(input, 'mouse3')
  520. messenger.send('DIRECT-mouse3', sentArgs = [modifiers])
  521. elif input == 'shift':
  522. self.fShift = 1
  523. elif input == 'shift-up':
  524. self.fShift = 0
  525. elif input == 'control':
  526. self.fControl = 1
  527. # [gjeon] to update control key information while mouse1 is pressed
  528. if self.fMouse1:
  529. modifiers = DIRECT_NO_MOD
  530. modifiers |= DIRECT_CONTROL_MOD
  531. messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
  532. elif input == 'control-up':
  533. self.fControl = 0
  534. elif input == 'alt':
  535. if self.fAlt:
  536. return
  537. self.fAlt = 1
  538. # [gjeon] to update alt key information while mouse1 is pressed
  539. if self.fMouse1:
  540. modifiers = DIRECT_NO_MOD
  541. modifiers |= DIRECT_ALT_MOD
  542. messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
  543. elif self.fMouse2:
  544. modifiers = DIRECT_NO_MOD
  545. modifiers |= DIRECT_ALT_MOD
  546. messenger.send('DIRECT-mouse2', sentArgs = [modifiers])
  547. elif self.fMouse3:
  548. modifiers = DIRECT_NO_MOD
  549. modifiers |= DIRECT_ALT_MOD
  550. messenger.send('DIRECT-mouse3', sentArgs = [modifiers])
  551. elif input == 'alt-up':
  552. self.fAlt = 0
  553. #Pass along certain events if this display is a cluster client
  554. if self.clusterMode == 'client':
  555. if input in self.passThroughKeys:
  556. self.cluster('messenger.send("%s")' % input, 0)
  557. def doSetActiveParent(self):
  558. if self.selected.last:
  559. self.setActiveParent(self.selected.last)
  560. def doReparent(self):
  561. if self.selected.last:
  562. self.reparent(self.selected.last)
  563. def doWrtReparent(self):
  564. if self.selected.last:
  565. self.reparent(self.selected.last, fWrt = 1)
  566. def doSelect(self):
  567. if self.selected.last:
  568. self.select(self.selected.last)
  569. def getModifiers(self, input, base):
  570. modifiers = DIRECT_NO_MOD
  571. modifierString = input[: input.find(base)]
  572. if modifierString.find('shift') != -1:
  573. modifiers |= DIRECT_SHIFT_MOD
  574. if modifierString.find('control') != -1:
  575. modifiers |= DIRECT_CONTROL_MOD
  576. if modifierString.find('alt') != -1:
  577. modifiers |= DIRECT_ALT_MOD
  578. return modifiers
  579. def gotShift(self, modifiers):
  580. return modifiers & DIRECT_SHIFT_MOD
  581. def gotControl(self, modifiers):
  582. return modifiers & DIRECT_CONTROL_MOD
  583. def gotAlt(self, modifiers):
  584. return modifiers & DIRECT_ALT_MOD
  585. def setFScaleWidgetByCam(self, flag):
  586. self.fScaleWidgetByCam = flag
  587. if flag:
  588. taskMgr.add(self.widgetResizeTask, 'DIRECTWidgetResize')
  589. else:
  590. taskMgr.remove('DIRECTWidgetResize')
  591. def widgetResizeTask(self, state):
  592. if not taskMgr.hasTaskNamed('resizeObjectHandles'):
  593. dnp = self.selected.last
  594. if dnp:
  595. direct = base.direct
  596. if self.manipulationControl.fMultiView:
  597. for i in range(3):
  598. sf = 30.0 * direct.drList[i].orthoFactor
  599. self.manipulationControl.widgetList[i].setDirectScalingFactor(sf)
  600. nodeCamDist = Vec3(dnp.getPos(base.camList[3])).length()
  601. sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList[3].fovV))
  602. self.manipulationControl.widgetList[3].setDirectScalingFactor(sf)
  603. else:
  604. nodeCamDist = Vec3(dnp.getPos(direct.camera)).length()
  605. sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList.getCurrentDr().fovV))
  606. self.widget.setDirectScalingFactor(sf)
  607. return Task.cont
  608. def select(self, nodePath, fMultiSelect = 0,
  609. fSelectTag = 1, fResetAncestry = 1, fLEPane=0, fUndo=1):
  610. messenger.send('DIRECT-select', [nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo])
  611. def selectCB(self, nodePath, fMultiSelect = 0,
  612. fSelectTag = 1, fResetAncestry = 1, fLEPane = 0, fUndo=1):
  613. dnp = self.selected.select(nodePath, fMultiSelect, fSelectTag)
  614. if dnp:
  615. messenger.send('DIRECT_preSelectNodePath', [dnp])
  616. if fResetAncestry:
  617. # Update ancestry
  618. self.ancestry = dnp.getAncestors()
  619. self.ancestryIndex = 0
  620. # Update the selectedNPReadout
  621. self.selectedNPReadout.reparentTo(base.a2dBottomLeft)
  622. self.selectedNPReadout.setText(
  623. 'Selected:' + dnp.getName())
  624. # Show the manipulation widget
  625. if self.manipulationControl.fMultiView:
  626. for widget in self.manipulationControl.widgetList:
  627. widget.showWidget()
  628. else:
  629. self.widget.showWidget()
  630. editTypes = self.manipulationControl.getEditTypes([dnp])
  631. if (editTypes & EDIT_TYPE_UNEDITABLE) == EDIT_TYPE_UNEDITABLE:
  632. self.manipulationControl.disableWidgetMove()
  633. else:
  634. self.manipulationControl.enableWidgetMove()
  635. # Update camera controls coa to this point
  636. # Coa2Camera = Coa2Dnp * Dnp2Camera
  637. mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera)
  638. row = mCoa2Camera.getRow(3)
  639. coa = Vec3(row[0], row[1], row[2])
  640. self.cameraControl.updateCoa(coa)
  641. # Adjust widgets size
  642. # This uses the additional scaling factor used to grow and
  643. # shrink the widget
  644. if not self.fScaleWidgetByCam: # [gjeon] for not scaling widget by distance from camera
  645. if self.manipulationControl.fMultiView:
  646. for widget in self.manipulationControl.widgetList:
  647. widget.setScalingFactor(dnp.getRadius())
  648. else:
  649. self.widget.setScalingFactor(dnp.getRadius())
  650. # Spawn task to have object handles follow the selected object
  651. taskMgr.remove('followSelectedNodePath')
  652. t = Task.Task(self.followSelectedNodePathTask)
  653. t.dnp = dnp
  654. taskMgr.add(t, 'followSelectedNodePath')
  655. # Send an message marking the event
  656. messenger.send('DIRECT_selectedNodePath', [dnp])
  657. messenger.send('DIRECT_selectedNodePath_fMulti_fTag', [dnp, fMultiSelect, fSelectTag])
  658. messenger.send('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', [dnp, fMultiSelect, fSelectTag, fLEPane])
  659. def followSelectedNodePathTask(self, state):
  660. mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render)
  661. decomposeMatrix(mCoa2Render,
  662. self.scale, self.hpr, self.pos,
  663. CSDefault)
  664. self.widget.setPosHpr(self.pos, self.hpr)
  665. return Task.cont
  666. def deselect(self, nodePath):
  667. dnp = self.selected.deselect(nodePath)
  668. if dnp:
  669. # Hide the manipulation widget
  670. if self.manipulationControl.fMultiView:
  671. for widget in self.manipulationControl.widgetList:
  672. widget.hideWidget()
  673. else:
  674. self.widget.hideWidget()
  675. self.selectedNPReadout.reparentTo(hidden)
  676. self.selectedNPReadout.setText(' ')
  677. taskMgr.remove('followSelectedNodePath')
  678. self.ancestry = []
  679. # Send an message marking the event
  680. messenger.send('DIRECT_deselectedNodePath', [dnp])
  681. def deselectAll(self):
  682. messenger.send('DIRECT-preDeselectAll')
  683. def deselectAllCB(self):
  684. self.selected.deselectAll()
  685. # Hide the manipulation widget
  686. if self.manipulationControl.fMultiView:
  687. for widget in self.manipulationControl.widgetList:
  688. widget.hideWidget()
  689. else:
  690. self.widget.hideWidget()
  691. self.selectedNPReadout.reparentTo(hidden)
  692. self.selectedNPReadout.setText(' ')
  693. taskMgr.remove('followSelectedNodePath')
  694. messenger.send('DIRECT_deselectAll')
  695. def setActiveParent(self, nodePath = None):
  696. # Record new parent
  697. self.activeParent = nodePath
  698. # Update the activeParentReadout
  699. self.activeParentReadout.reparentTo(base.a2dBottomLeft)
  700. self.activeParentReadout.setText(
  701. 'Active Reparent Target:' + nodePath.getName())
  702. # Alert everyone else
  703. messenger.send('DIRECT_activeParent', [self.activeParent])
  704. def reparent(self, nodePath = None, fWrt = 0):
  705. if (nodePath and self.activeParent and
  706. self.isNotCycle(nodePath, self.activeParent)):
  707. oldParent = nodePath.getParent()
  708. if fWrt:
  709. nodePath.wrtReparentTo(self.activeParent)
  710. else:
  711. nodePath.reparentTo(self.activeParent)
  712. # Alert everyone else
  713. messenger.send('DIRECT_reparent',
  714. [nodePath, oldParent, self.activeParent])
  715. # [gjeon] for others who needs fWrt information
  716. messenger.send('DIRECT_reparent_fWrt',
  717. [nodePath, oldParent, self.activeParent, fWrt])
  718. def isNotCycle(self, nodePath, parent):
  719. if nodePath == parent:
  720. print('DIRECT.reparent: Invalid parent')
  721. return 0
  722. elif parent.hasParent():
  723. return self.isNotCycle(nodePath, parent.getParent())
  724. else:
  725. return 1
  726. def flash(self, nodePath = 'None Given'):
  727. """ Highlight an object by setting it red for a few seconds """
  728. # Clean up any existing task
  729. taskMgr.remove('flashNodePath')
  730. # Spawn new task if appropriate
  731. if nodePath == 'None Given':
  732. # If nothing specified, try selected node path
  733. nodePath = self.selected.last
  734. if nodePath:
  735. if nodePath.hasColor():
  736. doneColor = nodePath.getColor()
  737. flashColor = VBase4(1) - doneColor
  738. flashColor.setW(1)
  739. else:
  740. doneColor = None
  741. flashColor = VBase4(1, 0, 0, 1)
  742. # Temporarily set node path color
  743. nodePath.setColor(flashColor)
  744. # Clean up color in a few seconds
  745. t = taskMgr.doMethodLater(DIRECT_FLASH_DURATION,
  746. # This is just a dummy task
  747. self.flashDummy,
  748. 'flashNodePath',)
  749. t.nodePath = nodePath
  750. t.doneColor = doneColor
  751. # This really does all the work
  752. t.setUponDeath(self.flashDone)
  753. def flashDummy(self, state):
  754. # Real work is done in upon death function
  755. return Task.done
  756. def flashDone(self, state):
  757. # Return node Path to original state
  758. if state.nodePath.isEmpty():
  759. # Node path doesn't exist anymore, bail
  760. return
  761. if state.doneColor:
  762. state.nodePath.setColor(state.doneColor)
  763. else:
  764. state.nodePath.clearColor()
  765. def fitOnNodePath(self, nodePath = 'None Given'):
  766. if nodePath == 'None Given':
  767. # If nothing specified, try selected node path
  768. nodePath = self.selected.last
  769. base.direct.select(nodePath)
  770. def fitTask(state, self = self):
  771. self.cameraControl.fitOnWidget()
  772. return Task.done
  773. taskMgr.doMethodLater(0.1, fitTask, 'manipulateCamera')
  774. def isolate(self, nodePath = 'None Given'):
  775. """ Show a node path and hide its siblings """
  776. # First kill the flashing task to avoid complications
  777. taskMgr.remove('flashNodePath')
  778. # Use currently selected node path if node selected
  779. if nodePath == 'None Given':
  780. nodePath = self.selected.last
  781. # Do we have a node path?
  782. if nodePath:
  783. # Yes, show everything in level
  784. self.showAllDescendants(nodePath.getParent())
  785. # Now hide all of this node path's siblings
  786. for sib in nodePath.getParent().getChildren():
  787. if sib.node() != nodePath.node():
  788. sib.hide()
  789. def toggleVis(self, nodePath = 'None Given'):
  790. """ Toggle visibility of node path """
  791. # First kill the flashing task to avoid complications
  792. taskMgr.remove('flashNodePath')
  793. if nodePath == 'None Given':
  794. # If nothing specified, try selected node path
  795. nodePath = self.selected.last
  796. if nodePath:
  797. # Now toggle node path's visibility state
  798. if nodePath.isHidden():
  799. nodePath.show()
  800. else:
  801. nodePath.hide()
  802. def removeNodePath(self, nodePath = 'None Given'):
  803. if nodePath == 'None Given':
  804. # If nothing specified, try selected node path
  805. nodePath = self.selected.last
  806. if nodePath:
  807. nodePath.removeNode()
  808. def removeAllSelected(self):
  809. self.selected.removeAll()
  810. def showAllDescendants(self, nodePath = None):
  811. """ Show the level and its descendants """
  812. if nodePath is None:
  813. nodePath = base.render
  814. if not isinstance(nodePath, CollisionNode):
  815. nodePath.show()
  816. for child in nodePath.getChildren():
  817. self.showAllDescendants(child)
  818. def upAncestry(self):
  819. if self.ancestry:
  820. l = len(self.ancestry)
  821. i = self.ancestryIndex + 1
  822. if i < l:
  823. np = self.ancestry[i]
  824. name = np.getName()
  825. if (name != 'render') and (name != 'renderTop'):
  826. self.ancestryIndex = i
  827. self.select(np, 0, 0)
  828. self.flash(np)
  829. def downAncestry(self):
  830. if self.ancestry:
  831. l = len(self.ancestry)
  832. i = self.ancestryIndex - 1
  833. if i >= 0:
  834. np = self.ancestry[i]
  835. name = np.getName()
  836. if (name != 'render') and (name != 'renderTop'):
  837. self.ancestryIndex = i
  838. self.select(np, 0, 0)
  839. self.flash(np)
  840. def getAndSetName(self, nodePath):
  841. """ Prompt user for new node path name """
  842. from tkinter.simpledialog import askstring
  843. newName = askstring('Node Path: ' + nodePath.getName(),
  844. 'Enter new name:')
  845. if newName:
  846. nodePath.setName(newName)
  847. messenger.send('DIRECT_nodePathSetName', [nodePath, newName])
  848. # UNDO REDO FUNCTIONS
  849. def pushUndo(self, nodePathList, fResetRedo = 1):
  850. # Assemble group of changes
  851. undoGroup = []
  852. for nodePath in nodePathList:
  853. t = nodePath.getTransform()
  854. undoGroup.append([nodePath, t])
  855. # Now record group
  856. self.undoList.append(undoGroup)
  857. # Truncate list
  858. self.undoList = self.undoList[-25:]
  859. # Alert anyone who cares
  860. messenger.send('DIRECT_pushUndo')
  861. if fResetRedo and (nodePathList != []):
  862. self.redoList = []
  863. messenger.send('DIRECT_redoListEmpty')
  864. def popUndoGroup(self):
  865. # Get last item
  866. undoGroup = self.undoList[-1]
  867. # Strip last item off of undo list
  868. self.undoList = self.undoList[:-1]
  869. # Update state of undo button
  870. if not self.undoList:
  871. messenger.send('DIRECT_undoListEmpty')
  872. # Return last item
  873. return undoGroup
  874. def pushRedo(self, nodePathList):
  875. # Assemble group of changes
  876. redoGroup = []
  877. for nodePath in nodePathList:
  878. t = nodePath.getTransform()
  879. redoGroup.append([nodePath, t])
  880. # Now record redo group
  881. self.redoList.append(redoGroup)
  882. # Truncate list
  883. self.redoList = self.redoList[-25:]
  884. # Alert anyone who cares
  885. messenger.send('DIRECT_pushRedo')
  886. def popRedoGroup(self):
  887. # Get last item
  888. redoGroup = self.redoList[-1]
  889. # Strip last item off of redo list
  890. self.redoList = self.redoList[:-1]
  891. # Update state of redo button
  892. if not self.redoList:
  893. messenger.send('DIRECT_redoListEmpty')
  894. # Return last item
  895. return redoGroup
  896. def undo(self):
  897. if self.undoList:
  898. # Get last item off of redo list
  899. undoGroup = self.popUndoGroup()
  900. # Record redo information
  901. nodePathList = [x[0] for x in undoGroup]
  902. self.pushRedo(nodePathList)
  903. # Now undo xform for group
  904. for pose in undoGroup:
  905. # Undo xform
  906. pose[0].setTransform(pose[1])
  907. # Alert anyone who cares
  908. messenger.send('DIRECT_undo', [nodePathList])
  909. def redo(self):
  910. if self.redoList:
  911. # Get last item off of redo list
  912. redoGroup = self.popRedoGroup()
  913. # Record undo information
  914. nodePathList = [x[0] for x in redoGroup]
  915. self.pushUndo(nodePathList, fResetRedo = 0)
  916. # Redo xform
  917. for pose in redoGroup:
  918. pose[0].setTransform(pose[1])
  919. # Alert anyone who cares
  920. messenger.send('DIRECT_redo', [nodePathList])
  921. # UTILITY FUNCTIONS
  922. def message(self, text):
  923. taskMgr.remove('hideDirectMessage')
  924. taskMgr.remove('hideDirectMessageLater')
  925. self.directMessageReadout.reparentTo(base.a2dTopLeft)
  926. self.directMessageReadout.setText(text)
  927. self.hideDirectMessageLater()
  928. def hideDirectMessageLater(self):
  929. taskMgr.doMethodLater(3.0, self.hideDirectMessage, 'hideDirectMessage')
  930. def hideDirectMessage(self, state):
  931. self.directMessageReadout.reparentTo(hidden)
  932. return Task.done
  933. def useObjectHandles(self):
  934. self.widget = self.manipulationControl.objectHandles
  935. self.widget.reparentTo(base.direct.group)
  936. def hideSelectedNPReadout(self):
  937. self.selectedNPReadout.reparentTo(hidden)
  938. def hideActiveParentReadout(self):
  939. self.activeParentReadout.reparentTo(hidden)
  940. def toggleWidgetVis(self):
  941. self.widget.toggleWidget()
  942. def setCOAMode(self, mode):
  943. self.coaMode = mode
  944. def isEnabled(self):
  945. return self.fEnabled
  946. def addUnpickable(self, item):
  947. for iRay in self.iRayList:
  948. iRay.addUnpickable(item)
  949. def removeUnpickable(self, item):
  950. for iRay in self.iRayList:
  951. iRay.removeUnpickable(item)
  952. class DisplayRegionContext(DirectObject):
  953. regionCount = 0
  954. def __init__(self, cam):
  955. self.cam = cam
  956. self.camNode = self.cam.node()
  957. self.camLens = self.camNode.getLens()
  958. # set lens change callback
  959. changeEvent = 'dr%d-change-event' % DisplayRegionContext.regionCount
  960. DisplayRegionContext.regionCount += 1
  961. self.camLens.setChangeEvent(changeEvent)
  962. self.accept(changeEvent, self.camUpdate)
  963. self.iRay = SelectionRay(self.cam)
  964. self.nearVec = Vec3(0)
  965. self.mouseX = 0.0
  966. self.mouseY = 0.0
  967. self.orthoFactor = 0.1
  968. # A Camera node can have more than one display region
  969. # associated with it. Here I assume that there is only
  970. # one display region per camera, since we are defining a
  971. # display region on a per-camera basis. See note in
  972. # DisplayRegionList.__init__()
  973. self.dr = self.camNode.getDisplayRegion(0)
  974. left = self.dr.getLeft()
  975. right = self.dr.getRight()
  976. bottom = self.dr.getBottom()
  977. top = self.dr.getTop()
  978. self.originX = left+right-1
  979. self.originY = top+bottom-1
  980. self.scaleX = 1.0/(right-left)
  981. self.scaleY = 1.0/(top-bottom)
  982. self.setOrientation()
  983. self.camUpdate()
  984. def __getitem__(self, key):
  985. return self.__dict__[key]
  986. def setOrientation(self):
  987. # MRM This assumes orientation is set on transform above cam
  988. hpr = self.cam.getHpr()
  989. if hpr[2] < 135 and hpr[2]>45 or hpr[2]>225 and hpr[2]<315:
  990. self.isSideways = 1
  991. elif hpr[2] > -135 and hpr[2] < -45 or hpr[2] < -225 and hpr[2] > -315:
  992. self.isSideways = 1
  993. else:
  994. self.isSideways = 0
  995. # The following take into consideration sideways displays
  996. def getHfov(self):
  997. if self.isSideways:
  998. return self.camLens.getVfov()
  999. else:
  1000. return self.camLens.getHfov()
  1001. def getVfov(self):
  1002. if self.isSideways:
  1003. return self.camLens.getHfov()
  1004. else:
  1005. return self.camLens.getVfov()
  1006. def setHfov(self, hfov):
  1007. if self.isSideways:
  1008. self.camLens.setFov(self.camLens.getHfov(), hfov)
  1009. else:
  1010. self.camLens.setFov(hfov, self.camLens.getVfov())
  1011. def setVfov(self, vfov):
  1012. if self.isSideways:
  1013. self.camLens.setFov(vfov, self.camLens.getVfov())
  1014. else:
  1015. self.camLens.setFov(self.camLens.getHfov(), vfov)
  1016. def setFov(self, hfov, vfov):
  1017. if self.isSideways:
  1018. self.camLens.setFov(vfov, hfov)
  1019. else:
  1020. self.camLens.setFov(hfov, vfov)
  1021. def getWidth(self):
  1022. prop = base.direct.win.getProperties()
  1023. if prop.hasSize():
  1024. return prop.getXSize()
  1025. else:
  1026. return 640
  1027. def getHeight(self):
  1028. prop = base.direct.win.getProperties()
  1029. if prop.hasSize():
  1030. return prop.getYSize()
  1031. else:
  1032. return 480
  1033. def updateFilmSize(self, width, height):
  1034. if self.camLens.__class__.__name__ == "OrthographicLens":
  1035. width *= self.orthoFactor
  1036. height *= self.orthoFactor
  1037. self.camLens.setFilmSize(width, height)
  1038. def camUpdate(self, lens = None):
  1039. # Window Data
  1040. self.near = self.camLens.getNear()
  1041. self.far = self.camLens.getFar()
  1042. self.fovH = self.camLens.getHfov()
  1043. self.fovV = self.camLens.getVfov()
  1044. self.nearWidth = math.tan(deg2Rad(self.fovH * 0.5)) * self.near * 2.0
  1045. self.nearHeight = math.tan(deg2Rad(self.fovV * 0.5)) * self.near * 2.0
  1046. self.left = -self.nearWidth * 0.5
  1047. self.right = self.nearWidth * 0.5
  1048. self.top = self.nearHeight * 0.5
  1049. self.bottom = -self.nearHeight * 0.5
  1050. def mouseUpdate(self):
  1051. # Mouse Data
  1052. # Last frame
  1053. self.mouseLastX = self.mouseX
  1054. self.mouseLastY = self.mouseY
  1055. # Values for this frame
  1056. # This ranges from -1 to 1
  1057. if base.mouseWatcherNode and base.mouseWatcherNode.hasMouse():
  1058. self.mouseX = base.mouseWatcherNode.getMouseX()
  1059. self.mouseY = base.mouseWatcherNode.getMouseY()
  1060. self.mouseX = (self.mouseX-self.originX)*self.scaleX
  1061. self.mouseY = (self.mouseY-self.originY)*self.scaleY
  1062. # Delta percent of window the mouse moved
  1063. self.mouseDeltaX = self.mouseX - self.mouseLastX
  1064. self.mouseDeltaY = self.mouseY - self.mouseLastY
  1065. self.nearVec.set((self.nearWidth*0.5) * self.mouseX,
  1066. self.near,
  1067. (self.nearHeight*0.5) * self.mouseY)
  1068. class DisplayRegionList(DirectObject):
  1069. def __init__(self):
  1070. self.displayRegionList = []
  1071. i = 0
  1072. # Things are funky if we are oobe
  1073. if (hasattr(base, 'oobeMode') and base.oobeMode):
  1074. # assume we only have one cam at this point
  1075. drc = DisplayRegionContext(base.cam)
  1076. self.displayRegionList.append(drc)
  1077. else:
  1078. # MRM: Doesn't properly handle multiple camera groups anymore
  1079. # Assumes everything is under main camera
  1080. # This is following the old way of setting up
  1081. # display regions. A display region is set up for
  1082. # each camera node in the scene graph. This was done
  1083. # so that only display regions in the scene graph are
  1084. # considered. The right way to do this is to set up
  1085. # a display region for each real display region, and then
  1086. # keep track of which are currently active (e.g. use a flag)
  1087. # processing only them.
  1088. for camIndex in range(len(base.camList)):
  1089. cam = base.camList[camIndex]
  1090. if cam.getName()=='<noname>':
  1091. cam.setName('Camera%d' % camIndex)
  1092. drc = DisplayRegionContext(cam)
  1093. self.displayRegionList.append(drc)
  1094. self.accept("DIRECT-mouse1", self.mouseUpdate)
  1095. self.accept("DIRECT-mouse2", self.mouseUpdate)
  1096. self.accept("DIRECT-mouse3", self.mouseUpdate)
  1097. self.accept("DIRECT-mouse1Up", self.mouseUpdate)
  1098. self.accept("DIRECT-mouse2Up", self.mouseUpdate)
  1099. self.accept("DIRECT-mouse3Up", self.mouseUpdate)
  1100. self.tryToGetCurrentDr = True
  1101. def __getitem__(self, index):
  1102. return self.displayRegionList[index]
  1103. def __len__(self):
  1104. return len(self.displayRegionList)
  1105. def updateContext(self):
  1106. self.contextTask(None)
  1107. def setNearFar(self, near, far):
  1108. for dr in self.displayRegionList:
  1109. dr.camLens.setNearFar(near, far)
  1110. def setNear(self, near):
  1111. for dr in self.displayRegionList:
  1112. dr.camLens.setNear(near)
  1113. def setFar(self, far):
  1114. for dr in self.displayRegionList:
  1115. dr.camLens.setFar(far)
  1116. def setFov(self, hfov, vfov):
  1117. for dr in self.displayRegionList:
  1118. dr.setFov(hfov, vfov)
  1119. def setHfov(self, fov):
  1120. for dr in self.displayRegionList:
  1121. dr.setHfov(fov)
  1122. def setVfov(self, fov):
  1123. for dr in self.displayRegionList:
  1124. dr.setVfov(fov)
  1125. def mouseUpdate(self, modifiers = DIRECT_NO_MOD):
  1126. for dr in self.displayRegionList:
  1127. dr.mouseUpdate()
  1128. #base.direct.dr = self.getCurrentDr()
  1129. def getCurrentDr(self):
  1130. if not self.tryToGetCurrentDr:
  1131. return base.direct.dr
  1132. for dr in self.displayRegionList:
  1133. if (dr.mouseX >= -1.0 and dr.mouseX <= 1.0 and
  1134. dr.mouseY >= -1.0 and dr.mouseY <= 1.0):
  1135. return dr
  1136. return self.displayRegionList[0]
  1137. def start(self):
  1138. # First shutdown any existing task
  1139. self.stop()
  1140. # Start a new context task
  1141. self.spawnContextTask()
  1142. def stop(self):
  1143. # Kill the existing context task
  1144. taskMgr.remove('DIRECTContextTask')
  1145. def spawnContextTask(self):
  1146. taskMgr.add(self.contextTask, 'DIRECTContextTask')
  1147. def removeContextTask(self):
  1148. taskMgr.remove('DIRECTContextTask')
  1149. def contextTask(self, state):
  1150. # Window Data
  1151. self.mouseUpdate()
  1152. # hack to test movement
  1153. return Task.cont
  1154. def addDisplayRegionContext(self, cam):
  1155. self.displayRegionList.append(DisplayRegionContext(cam))
  1156. def removeDisplayRegionContext(self, cam):
  1157. for drc in self.displayRegionList:
  1158. if drc.cam == cam:
  1159. self.displayRegionList.remove(drc)
  1160. break