DirectSession.py 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323
  1. import math
  2. import sys
  3. from panda3d.core import *
  4. from .DirectUtil import *
  5. from direct.showbase.DirectObject import DirectObject
  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 = (-1.0, -0.9), bg=Vec4(1, 1, 1, 1),
  63. 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 = (-1.0, -0.975), bg=Vec4(1, 1, 1, 1),
  70. 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 = (-1.0, 0.9), bg=Vec4(1, 1, 1, 1),
  77. 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 base.config.GetBool('want-vrpn', 0):
  88. from direct.directdevices import DirectDeviceManager
  89. self.deviceManager = DirectDeviceManager.DirectDeviceManager()
  90. # Automatically create any devices specified in config file
  91. joybox = base.config.GetString('vrpn-joybox-device', '')
  92. radamec = base.config.GetString('vrpn-radamec-device', '')
  93. fastrak = base.config.GetString('vrpn-fastrak-device', '')
  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.showbase import TkGlobal
  264. from direct.tkpanels import DirectSessionPanel
  265. self.panel = DirectSessionPanel.DirectSessionPanel(parent = tkroot)
  266. try:
  267. # Has the clusterMode been set externally (i.e. via the
  268. # bootstrap application?
  269. self.clusterMode = clusterMode
  270. except NameError:
  271. # Has the clusterMode been set via a config variable?
  272. self.clusterMode = base.config.GetString("cluster-mode", '')
  273. if self.clusterMode == 'client':
  274. self.cluster = createClusterClient()
  275. elif self.clusterMode == 'server':
  276. self.cluster = ClusterServer(base.camera, base.cam)
  277. else:
  278. self.cluster = DummyClusterClient()
  279. __builtins__['cluster'] = self.cluster
  280. def addPassThroughKey(self,key):
  281. self.passThroughKeys.append(key)
  282. def enable(self):
  283. # don't enable DIRECT if someone has posted DIRECTdisablePost
  284. if bboard.has(DirectSession.DIRECTdisablePost):
  285. return
  286. if self.fEnabled:
  287. return
  288. # Make sure old tasks are shut down
  289. self.disable()
  290. # Start all display region context tasks
  291. self.drList.spawnContextTask()
  292. if not self.fEnabledLight:
  293. # Turn on mouse Flying
  294. self.cameraControl.enableMouseFly()
  295. # Turn on object manipulation
  296. self.manipulationControl.enableManipulation()
  297. # Make sure list of selected items is reset
  298. self.selected.reset()
  299. # Accept appropriate hooks
  300. if not self.fEnabledLight:
  301. self.enableKeyEvents()
  302. self.enableMouseEvents()
  303. self.enableActionEvents()
  304. self.enableModifierEvents()
  305. # Set flag
  306. self.fEnabled = 1
  307. def enableLight(self):
  308. self.fEnabledLight = 1
  309. self.enable()
  310. def disable(self):
  311. # Shut down all display region context tasks
  312. self.drList.removeContextTask()
  313. # Turn off camera fly
  314. self.cameraControl.disableMouseFly()
  315. # Turn off object manipulation
  316. self.deselectAll()
  317. self.manipulationControl.disableManipulation()
  318. self.disableKeyEvents()
  319. self.disableModifierEvents()
  320. self.disableMouseEvents()
  321. self.disableActionEvents()
  322. # Kill tasks
  323. taskMgr.remove('flashNodePath')
  324. taskMgr.remove('hideDirectMessage')
  325. taskMgr.remove('hideDirectMessageLater')
  326. # Set flag
  327. self.fEnabled = 0
  328. def toggleDirect(self):
  329. if self.fEnabled:
  330. self.disable()
  331. else:
  332. self.enable()
  333. def minimumConfiguration(self):
  334. # Remove context task
  335. self.drList.removeContextTask()
  336. # Turn off camera fly
  337. self.cameraControl.disableMouseFly()
  338. # Ignore keyboard and action events
  339. self.disableKeyEvents()
  340. self.disableActionEvents()
  341. # But let mouse events pass through
  342. self.enableMouseEvents()
  343. self.enableModifierEvents()
  344. def oobe(self):
  345. # If oobeMode was never set, set it to false and create the
  346. # structures we need to implement OOBE.
  347. try:
  348. self.oobeMode
  349. except:
  350. self.oobeMode = 0
  351. self.oobeCamera = hidden.attachNewNode('oobeCamera')
  352. self.oobeVis = loader.loadModel('models/misc/camera')
  353. if self.oobeVis:
  354. self.oobeVis.node().setFinal(1)
  355. if self.oobeMode:
  356. # Position a target point to lerp the oobe camera to
  357. base.direct.cameraControl.camManipRef.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
  358. ival = self.oobeCamera.posHprInterval(
  359. 2.0, pos = Point3(0), hpr = Vec3(0),
  360. other = base.direct.cameraControl.camManipRef,
  361. blendType = 'easeInOut')
  362. ival = Sequence(ival, Func(self.endOOBE), name = 'oobeTransition')
  363. ival.start()
  364. else:
  365. # Place camera marker at true camera location
  366. self.oobeVis.reparentTo(self.trueCamera)
  367. # Remove any transformation on the models arc
  368. self.oobeVis.clearMat()
  369. # Make oobeCamera be a sibling of wherever camera is now.
  370. cameraParent = self.camera.getParent()
  371. # Prepare oobe camera
  372. self.oobeCamera.reparentTo(cameraParent)
  373. self.oobeCamera.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
  374. # Put camera under new oobe camera
  375. self.cam.reparentTo(self.oobeCamera)
  376. # Position a target point to lerp the oobe camera to
  377. base.direct.cameraControl.camManipRef.setPos(
  378. self.trueCamera, Vec3(-2, -20, 5))
  379. base.direct.cameraControl.camManipRef.lookAt(self.trueCamera)
  380. ival = self.oobeCamera.posHprInterval(
  381. 2.0, pos = Point3(0), hpr = Vec3(0),
  382. other = base.direct.cameraControl.camManipRef,
  383. blendType = 'easeInOut')
  384. ival = Sequence(ival, Func(self.beginOOBE), name = 'oobeTransition')
  385. ival.start()
  386. def beginOOBE(self):
  387. # Make sure we've reached our final destination
  388. self.oobeCamera.setPosHpr(base.direct.cameraControl.camManipRef, 0, 0, 0, 0, 0, 0)
  389. base.direct.camera = self.oobeCamera
  390. self.oobeMode = 1
  391. def endOOBE(self):
  392. # Make sure we've reached our final destination
  393. self.oobeCamera.setPosHpr(self.trueCamera, 0, 0, 0, 0, 0, 0)
  394. # Disable OOBE mode.
  395. self.cam.reparentTo(self.trueCamera)
  396. base.direct.camera = self.trueCamera
  397. # Get rid of ancillary node paths
  398. self.oobeVis.reparentTo(hidden)
  399. self.oobeCamera.reparentTo(hidden)
  400. self.oobeMode = 0
  401. def destroy(self):
  402. self.disable()
  403. def reset(self):
  404. self.enable()
  405. # EVENT FUNCTIONS
  406. def enableActionEvents(self):
  407. for event in self.actionEvents:
  408. self.accept(event[0], event[1], extraArgs = event[2:])
  409. def enableModifierEvents(self):
  410. for event in self.modifierEvents:
  411. self.accept(event, self.inputHandler, [event])
  412. def enableKeyEvents(self):
  413. for event in self.keyEvents:
  414. self.accept(event, self.inputHandler, [event])
  415. def enableMouseEvents(self):
  416. for event in self.mouseEvents:
  417. self.accept(event, self.inputHandler, [event])
  418. def disableActionEvents(self):
  419. for event, method in self.actionEvents:
  420. self.ignore(event)
  421. def disableModifierEvents(self):
  422. for event in self.modifierEvents:
  423. self.ignore(event)
  424. def disableKeyEvents(self):
  425. for event in self.keyEvents:
  426. self.ignore(event)
  427. def disableMouseEvents(self):
  428. for event in self.mouseEvents:
  429. self.ignore(event)
  430. def inputHandler(self, input):
  431. if not hasattr(self, 'oobeMode') or self.oobeMode == 0:
  432. # [gjeon] change current camera dr, iRay, mouseWatcher accordingly to support multiple windows
  433. if base.direct.manipulationControl.fMultiView:
  434. # handling orphan events
  435. if self.fMouse1 and 'mouse1' not in input or\
  436. self.fMouse2 and 'mouse2' not in input or\
  437. self.fMouse3 and 'mouse3' not in input:
  438. if input.endswith('-up') or\
  439. input not in self.modifierEvents:
  440. # to handle orphan events
  441. return
  442. if (self.fMouse1 == 0 and 'mouse1-up' in input) or\
  443. (self.fMouse2 == 0 and 'mouse2-up' in input) or\
  444. (self.fMouse3 == 0 and 'mouse3-up' in input):
  445. # to handle orphan events
  446. return
  447. if (self.fMouse1 or self.fMouse2 or self.fMouse3) and\
  448. input[4:7] != base.direct.camera.getName()[:3] and\
  449. input.endswith('-up'):
  450. # to handle orphan events
  451. return
  452. winCtrl = None
  453. possibleWinCtrls = []
  454. for cWinCtrl in base.winControls:
  455. if cWinCtrl.mouseWatcher.node().hasMouse():
  456. possibleWinCtrls.append(cWinCtrl)
  457. if len(possibleWinCtrls) == 1:
  458. winCtrl = possibleWinCtrls[0]
  459. elif len(possibleWinCtrls) > 1:
  460. for cWinCtrl in possibleWinCtrls:
  461. if (input.endswith('-up') and\
  462. not input in self.modifierEvents and\
  463. not input in self.mouseEvents) or\
  464. (input in self.mouseEvents):
  465. if input[4:7] == cWinCtrl.camera.getName()[:3]:
  466. winCtrl = cWinCtrl
  467. else:
  468. if input[4:7] != cWinCtrl.camera.getName()[:3]:
  469. winCtrl = cWinCtrl
  470. if winCtrl is None:
  471. return
  472. if input not in self.modifierEvents:
  473. self.win = winCtrl.win
  474. self.camera = winCtrl.camera
  475. self.trueCamera = self.camera
  476. self.cam = NodePath(winCtrl.camNode)
  477. self.camNode = winCtrl.camNode
  478. if hasattr(winCtrl, 'grid'):
  479. base.direct.grid = winCtrl.grid
  480. base.direct.dr = base.direct.drList[base.camList.index(NodePath(winCtrl.camNode))]
  481. base.direct.iRay = base.direct.dr.iRay
  482. base.mouseWatcher = winCtrl.mouseWatcher
  483. base.mouseWatcherNode = winCtrl.mouseWatcher.node()
  484. base.direct.dr.mouseUpdate()
  485. LE_showInOneCam(self.selectedNPReadout, self.camera.getName())
  486. base.direct.widget = base.direct.manipulationControl.widgetList[base.camList.index(NodePath(winCtrl.camNode))]
  487. input = input[8:] # get rid of camera prefix
  488. if self.fAlt and 'alt' not in input and not input.endswith('-up'):
  489. input = 'alt-' + input
  490. if input.endswith('-repeat'):
  491. input = input[:-7]
  492. # Deal with keyboard and mouse input
  493. if input in self.hotKeyMap:
  494. keyDesc = self.hotKeyMap[input]
  495. messenger.send(keyDesc[1])
  496. elif input in self.speicalKeyMap:
  497. messenger.send(self.speicalKeyMap[input])
  498. elif input in self.directOnlyKeyMap:
  499. if self.fIgnoreDirectOnlyKeyMap:
  500. return
  501. keyDesc = self.directOnlyKeyMap[input]
  502. messenger.send(keyDesc[1])
  503. elif input == 'mouse1-up':
  504. self.fMouse1 = 0 # [gjeon] to update alt key information while mouse1 is pressed
  505. messenger.send('DIRECT-mouse1Up')
  506. elif input.find('mouse1') != -1:
  507. self.fMouse1 = 1 # [gjeon] to update alt key information while mouse1 is pressed
  508. modifiers = self.getModifiers(input, 'mouse1')
  509. messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
  510. elif input == 'mouse2-up':
  511. self.fMouse2 = 0
  512. messenger.send('DIRECT-mouse2Up')
  513. elif input.find('mouse2') != -1:
  514. self.fMouse2 = 1
  515. modifiers = self.getModifiers(input, 'mouse2')
  516. messenger.send('DIRECT-mouse2', sentArgs = [modifiers])
  517. elif input == 'mouse3-up':
  518. self.fMouse3 = 0
  519. messenger.send('DIRECT-mouse3Up')
  520. elif input.find('mouse3') != -1:
  521. self.fMouse3 = 1
  522. modifiers = self.getModifiers(input, 'mouse3')
  523. messenger.send('DIRECT-mouse3', sentArgs = [modifiers])
  524. elif input == 'shift':
  525. self.fShift = 1
  526. elif input == 'shift-up':
  527. self.fShift = 0
  528. elif input == 'control':
  529. self.fControl = 1
  530. # [gjeon] to update control key information while mouse1 is pressed
  531. if self.fMouse1:
  532. modifiers = DIRECT_NO_MOD
  533. modifiers |= DIRECT_CONTROL_MOD
  534. messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
  535. elif input == 'control-up':
  536. self.fControl = 0
  537. elif input == 'alt':
  538. if self.fAlt:
  539. return
  540. self.fAlt = 1
  541. # [gjeon] to update alt key information while mouse1 is pressed
  542. if self.fMouse1:
  543. modifiers = DIRECT_NO_MOD
  544. modifiers |= DIRECT_ALT_MOD
  545. messenger.send('DIRECT-mouse1', sentArgs = [modifiers])
  546. elif self.fMouse2:
  547. modifiers = DIRECT_NO_MOD
  548. modifiers |= DIRECT_ALT_MOD
  549. messenger.send('DIRECT-mouse2', sentArgs = [modifiers])
  550. elif self.fMouse3:
  551. modifiers = DIRECT_NO_MOD
  552. modifiers |= DIRECT_ALT_MOD
  553. messenger.send('DIRECT-mouse3', sentArgs = [modifiers])
  554. elif input == 'alt-up':
  555. self.fAlt = 0
  556. #Pass along certain events if this display is a cluster client
  557. if self.clusterMode == 'client':
  558. if input in self.passThroughKeys:
  559. self.cluster('messenger.send("%s")' % input, 0)
  560. def doSetActiveParent(self):
  561. if self.selected.last:
  562. self.setActiveParent(self.selected.last)
  563. def doReparent(self):
  564. if self.selected.last:
  565. self.reparent(self.selected.last)
  566. def doWrtReparent(self):
  567. if self.selected.last:
  568. self.reparent(self.selected.last, fWrt = 1)
  569. def doSelect(self):
  570. if self.selected.last:
  571. self.select(self.selected.last)
  572. def getModifiers(self, input, base):
  573. modifiers = DIRECT_NO_MOD
  574. modifierString = input[: input.find(base)]
  575. if modifierString.find('shift') != -1:
  576. modifiers |= DIRECT_SHIFT_MOD
  577. if modifierString.find('control') != -1:
  578. modifiers |= DIRECT_CONTROL_MOD
  579. if modifierString.find('alt') != -1:
  580. modifiers |= DIRECT_ALT_MOD
  581. return modifiers
  582. def gotShift(self, modifiers):
  583. return modifiers & DIRECT_SHIFT_MOD
  584. def gotControl(self, modifiers):
  585. return modifiers & DIRECT_CONTROL_MOD
  586. def gotAlt(self, modifiers):
  587. return modifiers & DIRECT_ALT_MOD
  588. def setFScaleWidgetByCam(self, flag):
  589. self.fScaleWidgetByCam = flag
  590. if flag:
  591. taskMgr.add(self.widgetResizeTask, 'DIRECTWidgetResize')
  592. else:
  593. taskMgr.remove('DIRECTWidgetResize')
  594. def widgetResizeTask(self, state):
  595. if not taskMgr.hasTaskNamed('resizeObjectHandles'):
  596. dnp = self.selected.last
  597. if dnp:
  598. if self.manipulationControl.fMultiView:
  599. for i in range(3):
  600. sf = 30.0 * direct.drList[i].orthoFactor
  601. self.manipulationControl.widgetList[i].setDirectScalingFactor(sf)
  602. nodeCamDist = Vec3(dnp.getPos(base.camList[3])).length()
  603. sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList[3].fovV))
  604. self.manipulationControl.widgetList[3].setDirectScalingFactor(sf)
  605. else:
  606. nodeCamDist = Vec3(dnp.getPos(direct.camera)).length()
  607. sf = 0.075 * nodeCamDist * math.tan(deg2Rad(direct.drList.getCurrentDr().fovV))
  608. self.widget.setDirectScalingFactor(sf)
  609. return Task.cont
  610. def select(self, nodePath, fMultiSelect = 0,
  611. fSelectTag = 1, fResetAncestry = 1, fLEPane=0, fUndo=1):
  612. messenger.send('DIRECT-select', [nodePath, fMultiSelect, fSelectTag, fResetAncestry, fLEPane, fUndo])
  613. def selectCB(self, nodePath, fMultiSelect = 0,
  614. fSelectTag = 1, fResetAncestry = 1, fLEPane = 0, fUndo=1):
  615. dnp = self.selected.select(nodePath, fMultiSelect, fSelectTag)
  616. if dnp:
  617. messenger.send('DIRECT_preSelectNodePath', [dnp])
  618. if fResetAncestry:
  619. # Update ancestry
  620. self.ancestry = dnp.getAncestors()
  621. self.ancestryIndex = 0
  622. # Update the selectedNPReadout
  623. self.selectedNPReadout.reparentTo(aspect2d)
  624. self.selectedNPReadout.setText(
  625. 'Selected:' + dnp.getName())
  626. # Show the manipulation widget
  627. if self.manipulationControl.fMultiView:
  628. for widget in self.manipulationControl.widgetList:
  629. widget.showWidget()
  630. else:
  631. self.widget.showWidget()
  632. editTypes = self.manipulationControl.getEditTypes([dnp])
  633. if (editTypes & EDIT_TYPE_UNEDITABLE == EDIT_TYPE_UNEDITABLE):
  634. self.manipulationControl.disableWidgetMove()
  635. else:
  636. self.manipulationControl.enableWidgetMove()
  637. # Update camera controls coa to this point
  638. # Coa2Camera = Coa2Dnp * Dnp2Camera
  639. mCoa2Camera = dnp.mCoa2Dnp * dnp.getMat(self.camera)
  640. row = mCoa2Camera.getRow(3)
  641. coa = Vec3(row[0], row[1], row[2])
  642. self.cameraControl.updateCoa(coa)
  643. # Adjust widgets size
  644. # This uses the additional scaling factor used to grow and
  645. # shrink the widget
  646. if not self.fScaleWidgetByCam: # [gjeon] for not scaling widget by distance from camera
  647. if self.manipulationControl.fMultiView:
  648. for widget in self.manipulationControl.widgetList:
  649. widget.setScalingFactor(dnp.getRadius())
  650. else:
  651. self.widget.setScalingFactor(dnp.getRadius())
  652. # Spawn task to have object handles follow the selected object
  653. taskMgr.remove('followSelectedNodePath')
  654. t = Task.Task(self.followSelectedNodePathTask)
  655. t.dnp = dnp
  656. taskMgr.add(t, 'followSelectedNodePath')
  657. # Send an message marking the event
  658. messenger.send('DIRECT_selectedNodePath', [dnp])
  659. messenger.send('DIRECT_selectedNodePath_fMulti_fTag', [dnp, fMultiSelect, fSelectTag])
  660. messenger.send('DIRECT_selectedNodePath_fMulti_fTag_fLEPane', [dnp, fMultiSelect, fSelectTag, fLEPane])
  661. def followSelectedNodePathTask(self, state):
  662. mCoa2Render = state.dnp.mCoa2Dnp * state.dnp.getMat(render)
  663. decomposeMatrix(mCoa2Render,
  664. self.scale, self.hpr, self.pos,
  665. CSDefault)
  666. self.widget.setPosHpr(self.pos, self.hpr)
  667. return Task.cont
  668. def deselect(self, nodePath):
  669. dnp = self.selected.deselect(nodePath)
  670. if dnp:
  671. # Hide the manipulation widget
  672. if self.manipulationControl.fMultiView:
  673. for widget in self.manipulationControl.widgetList:
  674. widget.hideWidget()
  675. else:
  676. self.widget.hideWidget()
  677. self.selectedNPReadout.reparentTo(hidden)
  678. self.selectedNPReadout.setText(' ')
  679. taskMgr.remove('followSelectedNodePath')
  680. self.ancestry = []
  681. # Send an message marking the event
  682. messenger.send('DIRECT_deselectedNodePath', [dnp])
  683. def deselectAll(self):
  684. messenger.send('DIRECT-preDeselectAll')
  685. def deselectAllCB(self):
  686. self.selected.deselectAll()
  687. # Hide the manipulation widget
  688. if self.manipulationControl.fMultiView:
  689. for widget in self.manipulationControl.widgetList:
  690. widget.hideWidget()
  691. else:
  692. self.widget.hideWidget()
  693. self.selectedNPReadout.reparentTo(hidden)
  694. self.selectedNPReadout.setText(' ')
  695. taskMgr.remove('followSelectedNodePath')
  696. messenger.send('DIRECT_deselectAll')
  697. def setActiveParent(self, nodePath = None):
  698. # Record new parent
  699. self.activeParent = nodePath
  700. # Update the activeParentReadout
  701. self.activeParentReadout.reparentTo(aspect2d)
  702. self.activeParentReadout.setText(
  703. 'Active Reparent Target:' + nodePath.getName())
  704. # Alert everyone else
  705. messenger.send('DIRECT_activeParent', [self.activeParent])
  706. def reparent(self, nodePath = None, fWrt = 0):
  707. if (nodePath and self.activeParent and
  708. self.isNotCycle(nodePath, self.activeParent)):
  709. oldParent = nodePath.getParent()
  710. if fWrt:
  711. nodePath.wrtReparentTo(self.activeParent)
  712. else:
  713. nodePath.reparentTo(self.activeParent)
  714. # Alert everyone else
  715. messenger.send('DIRECT_reparent',
  716. [nodePath, oldParent, self.activeParent])
  717. # [gjeon] for others who needs fWrt information
  718. messenger.send('DIRECT_reparent_fWrt',
  719. [nodePath, oldParent, self.activeParent, fWrt])
  720. def isNotCycle(self, nodePath, parent):
  721. if nodePath == parent:
  722. print('DIRECT.reparent: Invalid parent')
  723. return 0
  724. elif parent.hasParent():
  725. return self.isNotCycle(nodePath, parent.getParent())
  726. else:
  727. return 1
  728. def flash(self, nodePath = 'None Given'):
  729. """ Highlight an object by setting it red for a few seconds """
  730. # Clean up any existing task
  731. taskMgr.remove('flashNodePath')
  732. # Spawn new task if appropriate
  733. if nodePath == 'None Given':
  734. # If nothing specified, try selected node path
  735. nodePath = self.selected.last
  736. if nodePath:
  737. if nodePath.hasColor():
  738. doneColor = nodePath.getColor()
  739. flashColor = VBase4(1) - doneColor
  740. flashColor.setW(1)
  741. else:
  742. doneColor = None
  743. flashColor = VBase4(1, 0, 0, 1)
  744. # Temporarily set node path color
  745. nodePath.setColor(flashColor)
  746. # Clean up color in a few seconds
  747. t = taskMgr.doMethodLater(DIRECT_FLASH_DURATION,
  748. # This is just a dummy task
  749. self.flashDummy,
  750. 'flashNodePath',)
  751. t.nodePath = nodePath
  752. t.doneColor = doneColor
  753. # This really does all the work
  754. t.setUponDeath(self.flashDone)
  755. def flashDummy(self, state):
  756. # Real work is done in upon death function
  757. return Task.done
  758. def flashDone(self, state):
  759. # Return node Path to original state
  760. if state.nodePath.isEmpty():
  761. # Node path doesn't exist anymore, bail
  762. return
  763. if state.doneColor:
  764. state.nodePath.setColor(state.doneColor)
  765. else:
  766. state.nodePath.clearColor()
  767. def fitOnNodePath(self, nodePath = 'None Given'):
  768. if nodePath == 'None Given':
  769. # If nothing specified, try selected node path
  770. nodePath = self.selected.last
  771. base.direct.select(nodePath)
  772. def fitTask(state, self = self):
  773. self.cameraControl.fitOnWidget()
  774. return Task.done
  775. taskMgr.doMethodLater(0.1, fitTask, 'manipulateCamera')
  776. def isolate(self, nodePath = 'None Given'):
  777. """ Show a node path and hide its siblings """
  778. # First kill the flashing task to avoid complications
  779. taskMgr.remove('flashNodePath')
  780. # Use currently selected node path if node selected
  781. if nodePath == 'None Given':
  782. nodePath = self.selected.last
  783. # Do we have a node path?
  784. if nodePath:
  785. # Yes, show everything in level
  786. self.showAllDescendants(nodePath.getParent())
  787. # Now hide all of this node path's siblings
  788. for sib in nodePath.getParent().getChildren():
  789. if sib.node() != nodePath.node():
  790. sib.hide()
  791. def toggleVis(self, nodePath = 'None Given'):
  792. """ Toggle visibility of node path """
  793. # First kill the flashing task to avoid complications
  794. taskMgr.remove('flashNodePath')
  795. if nodePath == 'None Given':
  796. # If nothing specified, try selected node path
  797. nodePath = self.selected.last
  798. if nodePath:
  799. # Now toggle node path's visibility state
  800. if nodePath.isHidden():
  801. nodePath.show()
  802. else:
  803. nodePath.hide()
  804. def removeNodePath(self, nodePath = 'None Given'):
  805. if nodePath == 'None Given':
  806. # If nothing specified, try selected node path
  807. nodePath = self.selected.last
  808. if nodePath:
  809. nodePath.removeNode()
  810. def removeAllSelected(self):
  811. self.selected.removeAll()
  812. def showAllDescendants(self, nodePath = None):
  813. """ Show the level and its descendants """
  814. if nodePath is None:
  815. nodePath = base.render
  816. if not isinstance(nodePath, CollisionNode):
  817. nodePath.show()
  818. for child in nodePath.getChildren():
  819. self.showAllDescendants(child)
  820. def upAncestry(self):
  821. if self.ancestry:
  822. l = len(self.ancestry)
  823. i = self.ancestryIndex + 1
  824. if i < l:
  825. np = self.ancestry[i]
  826. name = np.getName()
  827. if (name != 'render') and (name != 'renderTop'):
  828. self.ancestryIndex = i
  829. self.select(np, 0, 0)
  830. self.flash(np)
  831. def downAncestry(self):
  832. if self.ancestry:
  833. l = len(self.ancestry)
  834. i = self.ancestryIndex - 1
  835. if i >= 0:
  836. np = self.ancestry[i]
  837. name = np.getName()
  838. if (name != 'render') and (name != 'renderTop'):
  839. self.ancestryIndex = i
  840. self.select(np, 0, 0)
  841. self.flash(np)
  842. def getAndSetName(self, nodePath):
  843. """ Prompt user for new node path name """
  844. if sys.version_info >= (3, 0):
  845. from tkinter.simpledialog import askstring
  846. else:
  847. from tkSimpleDialog import askstring
  848. newName = askstring('Node Path: ' + nodePath.getName(),
  849. 'Enter new name:')
  850. if newName:
  851. nodePath.setName(newName)
  852. messenger.send('DIRECT_nodePathSetName', [nodePath, newName])
  853. # UNDO REDO FUNCTIONS
  854. def pushUndo(self, nodePathList, fResetRedo = 1):
  855. # Assemble group of changes
  856. undoGroup = []
  857. for nodePath in nodePathList:
  858. t = nodePath.getTransform()
  859. undoGroup.append([nodePath, t])
  860. # Now record group
  861. self.undoList.append(undoGroup)
  862. # Truncate list
  863. self.undoList = self.undoList[-25:]
  864. # Alert anyone who cares
  865. messenger.send('DIRECT_pushUndo')
  866. if fResetRedo and (nodePathList != []):
  867. self.redoList = []
  868. messenger.send('DIRECT_redoListEmpty')
  869. def popUndoGroup(self):
  870. # Get last item
  871. undoGroup = self.undoList[-1]
  872. # Strip last item off of undo list
  873. self.undoList = self.undoList[:-1]
  874. # Update state of undo button
  875. if not self.undoList:
  876. messenger.send('DIRECT_undoListEmpty')
  877. # Return last item
  878. return undoGroup
  879. def pushRedo(self, nodePathList):
  880. # Assemble group of changes
  881. redoGroup = []
  882. for nodePath in nodePathList:
  883. t = nodePath.getTransform()
  884. redoGroup.append([nodePath, t])
  885. # Now record redo group
  886. self.redoList.append(redoGroup)
  887. # Truncate list
  888. self.redoList = self.redoList[-25:]
  889. # Alert anyone who cares
  890. messenger.send('DIRECT_pushRedo')
  891. def popRedoGroup(self):
  892. # Get last item
  893. redoGroup = self.redoList[-1]
  894. # Strip last item off of redo list
  895. self.redoList = self.redoList[:-1]
  896. # Update state of redo button
  897. if not self.redoList:
  898. messenger.send('DIRECT_redoListEmpty')
  899. # Return last item
  900. return redoGroup
  901. def undo(self):
  902. if self.undoList:
  903. # Get last item off of redo list
  904. undoGroup = self.popUndoGroup()
  905. # Record redo information
  906. nodePathList = [x[0] for x in undoGroup]
  907. self.pushRedo(nodePathList)
  908. # Now undo xform for group
  909. for pose in undoGroup:
  910. # Undo xform
  911. pose[0].setTransform(pose[1])
  912. # Alert anyone who cares
  913. messenger.send('DIRECT_undo', [nodePathList])
  914. def redo(self):
  915. if self.redoList:
  916. # Get last item off of redo list
  917. redoGroup = self.popRedoGroup()
  918. # Record undo information
  919. nodePathList = [x[0] for x in redoGroup]
  920. self.pushUndo(nodePathList, fResetRedo = 0)
  921. # Redo xform
  922. for pose in redoGroup:
  923. pose[0].setTransform(pose[1])
  924. # Alert anyone who cares
  925. messenger.send('DIRECT_redo', [nodePathList])
  926. # UTILITY FUNCTIONS
  927. def message(self, text):
  928. taskMgr.remove('hideDirectMessage')
  929. taskMgr.remove('hideDirectMessageLater')
  930. self.directMessageReadout.reparentTo(aspect2d)
  931. self.directMessageReadout.setText(text)
  932. self.hideDirectMessageLater()
  933. def hideDirectMessageLater(self):
  934. taskMgr.doMethodLater(3.0, self.hideDirectMessage, 'hideDirectMessage')
  935. def hideDirectMessage(self, state):
  936. self.directMessageReadout.reparentTo(hidden)
  937. return Task.done
  938. def useObjectHandles(self):
  939. self.widget = self.manipulationControl.objectHandles
  940. self.widget.reparentTo(base.direct.group)
  941. def hideSelectedNPReadout(self):
  942. self.selectedNPReadout.reparentTo(hidden)
  943. def hideActiveParentReadout(self):
  944. self.activeParentReadout.reparentTo(hidden)
  945. def toggleWidgetVis(self):
  946. self.widget.toggleWidget()
  947. def setCOAMode(self, mode):
  948. self.coaMode = mode
  949. def isEnabled(self):
  950. return self.fEnabled
  951. def addUnpickable(self, item):
  952. for iRay in self.iRayList:
  953. iRay.addUnpickable(item)
  954. def removeUnpickable(self, item):
  955. for iRay in self.iRayList:
  956. iRay.removeUnpickable(item)
  957. class DisplayRegionContext(DirectObject):
  958. regionCount = 0
  959. def __init__(self, cam):
  960. self.cam = cam
  961. self.camNode = self.cam.node()
  962. self.camLens = self.camNode.getLens()
  963. # set lens change callback
  964. changeEvent = 'dr%d-change-event' % DisplayRegionContext.regionCount
  965. DisplayRegionContext.regionCount += 1
  966. self.camLens.setChangeEvent(changeEvent)
  967. self.accept(changeEvent, self.camUpdate)
  968. self.iRay = SelectionRay(self.cam)
  969. self.nearVec = Vec3(0)
  970. self.mouseX = 0.0
  971. self.mouseY = 0.0
  972. self.orthoFactor = 0.1
  973. # A Camera node can have more than one display region
  974. # associated with it. Here I assume that there is only
  975. # one display region per camera, since we are defining a
  976. # display region on a per-camera basis. See note in
  977. # DisplayRegionList.__init__()
  978. try:
  979. self.dr = self.camNode.getDr(0)
  980. except:
  981. self.dr = self.camNode.getDisplayRegion(0)
  982. left = self.dr.getLeft()
  983. right = self.dr.getRight()
  984. bottom = self.dr.getBottom()
  985. top = self.dr.getTop()
  986. self.originX = left+right-1
  987. self.originY = top+bottom-1
  988. self.scaleX = 1.0/(right-left)
  989. self.scaleY = 1.0/(top-bottom)
  990. self.setOrientation()
  991. self.camUpdate()
  992. def __getitem__(self, key):
  993. return self.__dict__[key]
  994. def setOrientation(self):
  995. # MRM This assumes orientation is set on transform above cam
  996. hpr = self.cam.getHpr()
  997. if hpr[2] < 135 and hpr[2]>45 or hpr[2]>225 and hpr[2]<315:
  998. self.isSideways = 1
  999. elif hpr[2] > -135 and hpr[2] < -45 or hpr[2] < -225 and hpr[2] > -315:
  1000. self.isSideways = 1
  1001. else:
  1002. self.isSideways = 0
  1003. # The following take into consideration sideways displays
  1004. def getHfov(self):
  1005. if self.isSideways:
  1006. return self.camLens.getVfov()
  1007. else:
  1008. return self.camLens.getHfov()
  1009. def getVfov(self):
  1010. if self.isSideways:
  1011. return self.camLens.getHfov()
  1012. else:
  1013. return self.camLens.getVfov()
  1014. def setHfov(self, hfov):
  1015. if self.isSideways:
  1016. self.camLens.setFov(self.camLens.getHfov(), hfov)
  1017. else:
  1018. self.camLens.setFov(hfov, self.camLens.getVfov())
  1019. def setVfov(self, vfov):
  1020. if self.isSideways:
  1021. self.camLens.setFov(vfov, self.camLens.getVfov())
  1022. else:
  1023. self.camLens.setFov(self.camLens.getHfov(), vfov)
  1024. def setFov(self, hfov, vfov):
  1025. if self.isSideways:
  1026. self.camLens.setFov(vfov, hfov)
  1027. else:
  1028. self.camLens.setFov(hfov, vfov)
  1029. def getWidth(self):
  1030. prop = base.direct.win.getProperties()
  1031. if prop.hasSize():
  1032. return prop.getXSize()
  1033. else:
  1034. return 640
  1035. def getHeight(self):
  1036. prop = base.direct.win.getProperties()
  1037. if prop.hasSize():
  1038. return prop.getYSize()
  1039. else:
  1040. return 480
  1041. def updateFilmSize(self, width, height):
  1042. if self.camLens.__class__.__name__ == "OrthographicLens":
  1043. width *= self.orthoFactor
  1044. height *= self.orthoFactor
  1045. self.camLens.setFilmSize(width, height)
  1046. def camUpdate(self, lens = None):
  1047. # Window Data
  1048. self.near = self.camLens.getNear()
  1049. self.far = self.camLens.getFar()
  1050. self.fovH = self.camLens.getHfov()
  1051. self.fovV = self.camLens.getVfov()
  1052. self.nearWidth = math.tan(deg2Rad(self.fovH * 0.5)) * self.near * 2.0
  1053. self.nearHeight = math.tan(deg2Rad(self.fovV * 0.5)) * self.near * 2.0
  1054. self.left = -self.nearWidth * 0.5
  1055. self.right = self.nearWidth * 0.5
  1056. self.top = self.nearHeight * 0.5
  1057. self.bottom = -self.nearHeight * 0.5
  1058. def mouseUpdate(self):
  1059. # Mouse Data
  1060. # Last frame
  1061. self.mouseLastX = self.mouseX
  1062. self.mouseLastY = self.mouseY
  1063. # Values for this frame
  1064. # This ranges from -1 to 1
  1065. if base.mouseWatcherNode and base.mouseWatcherNode.hasMouse():
  1066. self.mouseX = base.mouseWatcherNode.getMouseX()
  1067. self.mouseY = base.mouseWatcherNode.getMouseY()
  1068. self.mouseX = (self.mouseX-self.originX)*self.scaleX
  1069. self.mouseY = (self.mouseY-self.originY)*self.scaleY
  1070. # Delta percent of window the mouse moved
  1071. self.mouseDeltaX = self.mouseX - self.mouseLastX
  1072. self.mouseDeltaY = self.mouseY - self.mouseLastY
  1073. self.nearVec.set((self.nearWidth*0.5) * self.mouseX,
  1074. self.near,
  1075. (self.nearHeight*0.5) * self.mouseY)
  1076. class DisplayRegionList(DirectObject):
  1077. def __init__(self):
  1078. self.displayRegionList = []
  1079. i = 0
  1080. # Things are funky if we are oobe
  1081. if (hasattr(base, 'oobeMode') and base.oobeMode):
  1082. # assume we only have one cam at this point
  1083. drc = DisplayRegionContext(base.cam)
  1084. self.displayRegionList.append(drc)
  1085. else:
  1086. # MRM: Doesn't properly handle multiple camera groups anymore
  1087. # Assumes everything is under main camera
  1088. # This is following the old way of setting up
  1089. # display regions. A display region is set up for
  1090. # each camera node in the scene graph. This was done
  1091. # so that only display regions in the scene graph are
  1092. # considered. The right way to do this is to set up
  1093. # a display region for each real display region, and then
  1094. # keep track of which are currently active (e.g. use a flag)
  1095. # processing only them.
  1096. for camIndex in range(len(base.camList)):
  1097. cam = base.camList[camIndex]
  1098. if cam.getName()=='<noname>':
  1099. cam.setName('Camera%d' % camIndex)
  1100. drc = DisplayRegionContext(cam)
  1101. self.displayRegionList.append(drc)
  1102. self.accept("DIRECT-mouse1", self.mouseUpdate)
  1103. self.accept("DIRECT-mouse2", self.mouseUpdate)
  1104. self.accept("DIRECT-mouse3", self.mouseUpdate)
  1105. self.accept("DIRECT-mouse1Up", self.mouseUpdate)
  1106. self.accept("DIRECT-mouse2Up", self.mouseUpdate)
  1107. self.accept("DIRECT-mouse3Up", self.mouseUpdate)
  1108. self.tryToGetCurrentDr = True
  1109. def __getitem__(self, index):
  1110. return self.displayRegionList[index]
  1111. def __len__(self):
  1112. return len(self.displayRegionList)
  1113. def updateContext(self):
  1114. self.contextTask(None)
  1115. def setNearFar(self, near, far):
  1116. for dr in self.displayRegionList:
  1117. dr.camLens.setNearFar(near, far)
  1118. def setNear(self, near):
  1119. for dr in self.displayRegionList:
  1120. dr.camLens.setNear(near)
  1121. def setFar(self, far):
  1122. for dr in self.displayRegionList:
  1123. dr.camLens.setFar(far)
  1124. def setFov(self, hfov, vfov):
  1125. for dr in self.displayRegionList:
  1126. dr.setFov(hfov, vfov)
  1127. def setHfov(self, fov):
  1128. for dr in self.displayRegionList:
  1129. dr.setHfov(fov)
  1130. def setVfov(self, fov):
  1131. for dr in self.displayRegionList:
  1132. dr.setVfov(fov)
  1133. def mouseUpdate(self, modifiers = DIRECT_NO_MOD):
  1134. for dr in self.displayRegionList:
  1135. dr.mouseUpdate()
  1136. #base.direct.dr = self.getCurrentDr()
  1137. def getCurrentDr(self):
  1138. if not self.tryToGetCurrentDr:
  1139. return base.direct.dr
  1140. for dr in self.displayRegionList:
  1141. if (dr.mouseX >= -1.0 and dr.mouseX <= 1.0 and
  1142. dr.mouseY >= -1.0 and dr.mouseY <= 1.0):
  1143. return dr
  1144. return self.displayRegionList[0]
  1145. def start(self):
  1146. # First shutdown any existing task
  1147. self.stop()
  1148. # Start a new context task
  1149. self.spawnContextTask()
  1150. def stop(self):
  1151. # Kill the existing context task
  1152. taskMgr.remove('DIRECTContextTask')
  1153. def spawnContextTask(self):
  1154. taskMgr.add(self.contextTask, 'DIRECTContextTask')
  1155. def removeContextTask(self):
  1156. taskMgr.remove('DIRECTContextTask')
  1157. def contextTask(self, state):
  1158. # Window Data
  1159. self.mouseUpdate()
  1160. # hack to test movement
  1161. return Task.cont
  1162. def addDisplayRegionContext(self, cam):
  1163. self.displayRegionList.append(DisplayRegionContext(cam))
  1164. def removeDisplayRegionContext(self, cam):
  1165. for drc in self.displayRegionList:
  1166. if drc.cam == cam:
  1167. self.displayRegionList.remove(drc)
  1168. break